5

I try to upload an image on my instagram, so I need to select path for upload files enter image description here

but I can't use form.file_field.send_keys(path) because Instagram manage upload via JS, so the form not exist, it's only when I click on button "+" then the "File Upload" window appear.

I try :

 @browser.send_keys @path
 @browser.send_keys :enter

but not works too...

I don't found a method to interact with this sub-windows "File Upload" to give the path of image.

Any idea?

EDIT :

<nav class="NXc7H  f11OC "><div class="_8MQSO ZoygQ "><div class=""><div class="rBWT5"></div><div class="KGiwt"><div class="A8wCM"><div class="BvyAW"><div class="q02Nz"><a class="_0TPg" href="/"><span class="glyphsSpriteHome__outline__24__grey_9 u-__7" aria-label="Home"></span></a></div><div class="q02Nz"><a class="_0TPg" href="/explore/"><span class="glyphsSpriteSearch__outline__24__grey_9 u-__7" aria-label="Search &amp; Explore"></span></a></div><div class="q02Nz _0TPg" role="menuitem" tabindex="0"><span class="glyphsSpriteNew_post__outline__24__grey_9 u-__7" aria-label="New Post" style=""></span></div><div class="q02Nz"><a class="_0TPg " href="/accounts/activity/"><span class="glyphsSpriteHeart__outline__24__grey_9 u-__7" aria-label="Activity"></span></a></div><div class="q02Nz"><a class="_0TPg" href="/tristan_grey_30/"><span class="glyphsSpriteUser__filled__24__grey_9 u-__7" aria-label="Profile"></span></a></div></div></div></div><form class="Q9en_" enctype="multipart/form-data" method="POST" role="presentation"><input accept="image/jpeg" class="tb_sK" type="file"></form></div></div></nav>

if I try using the <form> contain in <nav>, nothing happen, there is onClick event on "+" :

{
  !0 !== this.$_MobileNav2 && (this.$_MobileNav2 = !0, r(d[1]).logAction_DEPRECATED('cameraIconClick'), this.$_MobileNav3 ? (this.$_MobileNav3.selectFile(), this.props.onStartCreation()) : (i(d[2])('No image form'), this.props.onImageFormError()), this.$_MobileNav2 = !1)
}

It's manage by JS I think...

Matrix
  • 3,458
  • 6
  • 40
  • 76
  • 1
    Can you share the html of the `+` I believe there should be a input with file type which generally we use in other apps. – supputuri Apr 30 '19 at 16:18
  • @supputuri I already try, one by one each form of page, it works only for "image of profile", but not for send a post. I edit my post for html – Matrix Apr 30 '19 at 16:52
  • What about [`FileField#set`](https://www.rubydoc.info/github/watir/watir-classic/Watir/FileField#set-instance_method)? – orde May 05 '19 at 22:03
  • @orde same... it's not works. `send_keys` works on other classic form... – Matrix May 06 '19 at 00:15
  • 1
    The issue here is that Instagram wants to protect itself, from bots. The posting of images via interaction has been disabled. You can get around this issue via automation tools like AutoIt (for Windows). From your screenshot I assume you have linux, there you have tools like xautomation - https://www.hoopajoo.net/projects/xautomation.html or expect - https://core.tcl.tk/expect/index. – tukan May 06 '19 at 07:59
  • I can not access that page. I can only display the navbar on the bottom on my android phone, I can run an emulator and debug that page with my laptop, but the code is all minified and unreadable... Once you click on the + button to upload a picture, on android an intent will be triggered which opens the android library. If you want to get real help, you should give us an explanation on how to reproduce your scenario so that we can start thinking about a solution. – Fabrizio Bertoglio May 06 '19 at 18:43
  • 1
    @FabrizioBertoglio the scenario is simple : open Watir on instagram, connect on my account, and I need to add picture (and text) to publish with it... – Matrix May 06 '19 at 19:20
  • @Matrix Do you have a test account which can be shared? – supputuri May 06 '19 at 21:09
  • 1
    You cannot use Selenium to interact with OS level dialogue boxes, you will instead need to hook into the JS directly using a JavascriptExecutor. If you provide the site you are trying to work with we would be able to provide more help – Ardesco May 07 '19 at 08:16
  • @supputuri no I have only my personnal account :$ – Matrix May 07 '19 at 13:01
  • @Ardesco the site is Instagram, it said in my post ^^ – Matrix May 07 '19 at 13:04
  • 1
    oops, missed that, will have a look later. – Ardesco May 07 '19 at 13:08
  • How about adding an input file field to the form and attach the form submission event, by that way you can submit the path of the file directly using the custom input field. – supputuri May 09 '19 at 19:38

4 Answers4

1

You aren't going to like the answer, but Watir will not interact with that window opened up by the OS in any way. Going a step further, Ruby itself does not interact with these OS level dialogues.

There are a couple of things that you may want to reference to confirm this, and that's perfectly acceptable:

In any case, you are attempting to interact with an object that does not have a way of being interacted with through Ruby, let alone Watir, and thus your desired solution is impossible.

Your best case is the Capybara attach_file method. If that doesn't work, nothing is going to outside of a literal OS scripting language such as AutoIt or Sikuli

You can find the SikuliX project page here. DrapsTV did a roughly hour-long playlist about the setup and quickstart of SikuliX. The link to the first episode in the series is linked here.

Good luck.

Community
  • 1
  • 1
karnesJ.R
  • 326
  • 1
  • 11
  • for 1 & 2 proposition, it's for download, but in my case i'm in upload. for the last, I discover what Instagram manage the upload files by JS, so Capybara can't do better than Watir :'( – Matrix May 08 '19 at 10:41
  • I don't know AutoIt or Sikuli, I will search... In fact a little script to interact with this windows will be perfect... – Matrix May 08 '19 at 10:42
  • @Matrix The idea behind the first and second propositions is to show that the method that is generally accepted to solve downloads (avoid invoking the OS dialogue by specifying a default path) is not tenable for doing file uploading. I have amended my answer to include a link to Sikuli and would appreciate it if you would accept this answer if you feel that it provided you with enough information to resolve your problem. – karnesJ.R May 09 '19 at 19:09
1

I'm going to go with a bit of a JavaScript hack to expose the hidden <input type="file">. The first thing to do is identify the input type file on the page, then use some JavaScript to make it visible. Then once it is visible use send_keys to pass in the path to the local file and selenium should do the rest for you.

file_upload_element = @browser.file_field
@browser.execute_script("return arguments[0].setAttribute( 'style', 'display: inline !important')", file_upload_element)
file_upload_element.set(<path_to_local_file>)

Some caveats. I don't use Watir, I've tried to write the above code based on the Watir documentation and the code you have provided, it is a guess though. I can write it in a language I'm familiar with if that helps. I am hoping it's close enough to point you in the right direction though.

Ardesco
  • 7,281
  • 26
  • 49
  • can you show me the error you are seeing/a screenshot of the page after running the execute_script command? When I log into Instagram with a browser I don't see the same screen you are seeing above so it's possible there is some slightly different markup. – Ardesco May 10 '19 at 08:51
  • 1
    Note that it should actually be `@browser.file_field` (with identifiers if needed) – Justin Ko May 10 '19 at 12:56
  • Looks like I missed that when going through the docs, updated. – Ardesco May 10 '19 at 13:11
0

As mentioned the comments earlier, can you try appending the file input element to the html and then use that to upload the file.

# get the frame element or any button that opens the file upload window
ele = driver.find_element_by_id("frame/button id goes here")
# add a hidden file input ( might have to change the onchange event based on the events associated to the button in above line as you don't have a form)
driver.execute_script("var x=  document.createElement('INPUT');x.setAttribute('type', 'file'); x.setAttribute('onchange','this.form.submit()');x.setAttribute('hidden', 'true'); arguments[0].appendChild(x);",ele)
# send the picture path here ( this should upload the file)
driver.find_element_by_xpath("//input[@type='file']").send_keys("picture path should go here")

Can you please try this and let me know your outcome.

supputuri
  • 13,644
  • 2
  • 21
  • 39
  • 1
    This solution worked for [other user](https://stackoverflow.com/questions/56087759/python-3-selenium-os-how-to-upload-all-images-in-folder/56093862#56093862) but not on instagram. – supputuri May 13 '19 at 02:40
  • @Matrix Did you get a chance to test this approach? – supputuri May 18 '19 at 16:22
0

@browser.file_field.set file_upload works for me

I had to update my Chrome Driver which was little bit tricky on Windows. Belows is my complete script for upload to a Dropbox File Request:

require 'watir'

#setting the path to my updated ChromeDriver:
Selenium::WebDriver::Chrome::Service.driver_path = 'C:\#Ruby\#no_pub\install\chromedriver.exe'

class Dropbox_Request
    def initialize(url, file_upload)
        @browser = Watir::Browser.new
        @browser.goto url

        @browser.file_field.set  file_upload
        @browser.text_field(:name => 'fname').set "first" 
        @browser.text_field(:name => 'lname').set "last" 
        @browser.text_field(:name => 'email').set "email@gmail.com" 
        @browser.button(:class => ["button-primary", "submission-form__submit"]).click()
    end
end
Nathan
  • 412
  • 6
  • 16