81

How to upload a picture on a web application with the selenium testing tool? I am using python.

I tried many things, but nothing worked.

Nemo
  • 2,441
  • 2
  • 29
  • 63
Filip
  • 989
  • 1
  • 10
  • 8

20 Answers20

196

What I'm doing is this (make sure drv is an instance of webdriver):

drv.find_element_by_id("IdOfInputTypeFile").send_keys(os.getcwd()+"/image.png")

and then find your submit button and click it.

karloskar
  • 2,091
  • 1
  • 15
  • 10
  • 3
    Can you please elaborate what `os.getcwd()` does and where in your example `image.png` is located on your file system. – ChickenFeet Jun 29 '17 at 12:51
  • 7
    Sure! [`os.getcwd()`](https://docs.python.org/2/library/os.html#os.getcwd) returns the current working directory. `image.png` is located right next to the running script in the same directory. – karloskar Jul 02 '17 at 11:26
  • 3
    This is the perfect way to do it. I should point out that the form needs to have an ID and it helps if the button does too! – Sergio Lucero May 09 '18 at 12:47
  • What makes you say that Tobias K? What does not work? All my Selenium experience has come from Linux environments. – karloskar May 29 '19 at 13:08
  • So if I am actually looking at the spreadsheet, how can I upload the image / find the ID/Xpath – Celius Stingher Feb 21 '20 at 16:28
  • 1
    There is an upload button on the website where I want to upload my image.The upload buttons opens a dialog box for uploading image. But when I find the element(upload button) using class_name, I am not able to upload image using elem.send_keys('path/of/image'). What should I do? – Shashank Gupta Feb 24 '20 at 09:34
  • Side-note: Multiple-file upload is also possible with send_keys - see https://stackoverflow.com/questions/23955430/selenium-webdriver-upload-multiple-files – Joseph238 Mar 17 '21 at 23:17
  • Is anyone aware of a solution like this that supports supplying multiple files at once? – TryTryAgain Oct 18 '22 at 20:04
30

A very easy way to control components like windows file selector (or just your OS in general) is by using pyautogui. You can install pyautogui through pip

import pyautogui
... # set the webdriver etc.
...
...
element_present = EC.presence_of_element_located((By.XPATH, "//button[@title='Open file selector']"))  # Example xpath

WebDriverWait(self.driver, 10).until(element_present).click() # This opens the windows file selector

pyautogui.write('C:/path_to_file') 
pyautogui.press('enter')
XRaycat
  • 1,051
  • 3
  • 16
  • 28
  • 7
    I'm not sure why this was not given more votes. It is by far the most elegant and simple solution considering it is also cross platform. I was struggling for hours trying to find something that would work and was simple. I found had to make a couple of changes though because the `enter` option was not being recognized. `pyautogui.write(filepath, interval=0.25) pyautogui.press('return')` – eddyizm Feb 22 '20 at 17:59
  • That helped a lot! Just make sure you use python selenium. – Joe Mar 21 '20 at 16:56
  • 2
    Does this work when using selenium in "headless" mode where there is no actual browser gui being created? – alexpotato Apr 06 '20 at 14:56
  • @alexpotato No that's true, but if the file selection window turns up I think this could work. – XRaycat Apr 10 '20 at 20:38
  • @eddyizm I'm doing exactly what you suggested, but pyautogui hits enter in my ipynb notebook instead of the window to confirm the file choice. Do you know how to proceed? – R. Kulebyakin May 06 '20 at 09:49
  • 1
    @R.Kulebyakin I'm not 100% sure about this but If you have multiple screens you can try to move the browser window to your main screen since pyautogui can only control your main screen. – XRaycat May 06 '20 at 10:38
  • 1
    @XRaycat thanks for your reply! I fixed the problem by running both .write and .press in one cell. But now the file is just not being attached for some reason. Having said that I see how the path is typed and then the "enter" button is clicked... – R. Kulebyakin May 06 '20 at 10:53
  • 1
    `time.sleep(1)` before `pyautogui.write('C:/path_to_file')` guarantees reliable result I guess – YoussefDir Dec 02 '22 at 21:44
12

I am using fine-uploader, running selenium tests with pytest and this worked for me:

elm = driver.find_element_by_xpath("//input[@type='file']")
elm.send_keys(os.getcwd() + "/tests/sample_files/Figure1.tif")

No form submission or Enter key is needed in my case.

user5305519
  • 3,008
  • 4
  • 26
  • 44
AnaPana
  • 1,958
  • 19
  • 18
10

I added an answer for anyone looking to use deal with the annoying msofiledialogs. This is working off of saravanan's proposed solution, but more fleshed out for Python.

I had a similar problem with a script I'm working on for a company on the side. I'm attempting to upload documents for a company's clients, but due to the way their site worked, I could not utilize send_keys to directly send the path, so I had to rely on msofiledialog.

  1. You only need to install AutoIt https://pypi.python.org/pypi/PyAutoIt/0.3 or just "pip install -U pyautoit" through the cmd screen

  2. type "import autoit" on your script page

  3. Type the following before the file dialog pops up in your script:

    autoit.win_active("Open") autoit.control_send("Open","Edit1",r"C:\Users\uu\Desktop\TestUpload.txt") autoit.control_send("Open","Edit1","{ENTER}")

It will look for the open file dialog window and fill it out and press enter. "Open" is the title of my file dialog screen. Put the title of yours in place of "Open". There are more creative ways to utilize AutoIt's functions, but this is an easy, straightforward way for beginners.

Edit: DO NOT. DO NOT use control_send on most things if you can avoid it. It has a well-known issue of sending erroneous text. In my case, the colon in my file path was being turned into a semi colon. If you need to send input keys, it should be fine, however if you need to send text, use control_set_text. It has the same syntax.

autoit.control_set_text("Open","Edit1",r"C:\Users\uu\Desktop\TestUpload.txt")
Noctsol
  • 478
  • 1
  • 8
  • 13
  • 1
    Is this only for Windows? – Wildhammer Jun 29 '19 at 23:30
  • @Noctsol Please help me.Iam also using autoit but it is uploading sometimes & sometimes not able to identify file dialogue box – Vishav Gupta Apr 01 '20 at 07:25
  • I'm no longer doing this kind of thing, but if I had to guess. Are you triggering the file dialogue box on time? autoit should be reliable. Try adding a time.sleep(n) condition right before you call the auto. – Noctsol Apr 01 '20 at 14:07
7

All these approach wont work with modern image uploaders in olx !!! Alternative approach (only for windows )

1. Automation of windows can be done using Autoit 
2. Install Autoit and SciTe Script editor 
3. Autoit code :(imageupload.au3)

WinActivate("File Upload");  for chrome use "open" that is the name of the window that pops 
send("D:\images\image1.png");  path of the file
Send("{ENTER}")

4. compile it to get an .exe file(imageupload.exe)
5. Now from python call the .exe file like

import os
import os.system('C:\images\imageupload.exe') #path of the .exe file
saravanan
  • 398
  • 4
  • 13
  • 1
    can you give a clear example, do you import the exe and how do you call it exactly? – 2one2 Jul 27 '15 at 03:34
  • Nope! create a new autoit file with the three lines that I have given in my 3rd point. Refer this to convert it into .exe file https://www.autoitscript.com/autoit3/docs/intro/compiler.htm then you can call the exe file from python script using the two lines i have given in 5th point – saravanan Aug 27 '15 at 04:45
  • Some ideas for linux? – otto May 30 '19 at 16:59
6

Upload input control opens a native dialog (it is done by browser) so clicking on the control or browse button via Selenium will just pop the dialog and the test will hang.

The workaround is to set the value of the upload input via JavaScript (in Java it is done via JavascriptExecutor) and then submit the form.

See this question for sample in C#, I am sure there's also a way to call JavaScript in Python but I never used Selenium Python bindings

Community
  • 1
  • 1
Sergii Pozharov
  • 17,366
  • 4
  • 29
  • 30
  • This is not a valid solution, see https://stackoverflow.com/questions/29720794/jquery-select-input-file-and-also-set-it-to-another-input – Will Apr 17 '17 at 17:11
4

Here is the code that i used:

Imagepath = "C:\User\Desktop\image.png"
driver.find_element_by_xpath('//html/body/input').send_keys(Imagepath)
driver.find_element_by_xpath('//html/body/button').click()

I accept the Answer by karloskar. Note It is not working for FireFox (59). And it is works with Chrome Driver only.

Walucas
  • 2,549
  • 1
  • 21
  • 44
Arun K
  • 868
  • 10
  • 17
3
import win32com.client

shell = win32com.client.Dispatch("WScript.Shell")   
shell.Sendkeys("C:\text.txt")  
shell.Sendkeys("~")

Will resolve the issue

Jakob Bowyer
  • 33,878
  • 8
  • 76
  • 91
3

Use PyAutoGui if sendkeys function is not working on buttons.

sample code:

import pyautogui
driver.find_element_by_xpath("Enter Xpath of File upload button").click()
time.sleep(4) #waiting for window popup to open
pyautogui.write(r"C:\Users\AmarKumar\FilesForUploading\image.jpg") #path of File
pyautogui.press('enter')
Amar Kumar
  • 2,392
  • 2
  • 25
  • 33
3

You can easily add this one line of code to solve the problem:

driver.find_element_by_xpath("your fullpath").send_keys("C://1.png(your file root")

But pay attention, sometimes maybe you put a wrong xpath in first field. follow below steps for reach to rightful xpath:

  1. open the inspect and click exactly on the box which you want to upload the file.
  2. right click on the html code and select xpath full address from copy sub menu.
  3. paste the root in xpath field in the code.

enter image description here

Ozgur Bagci
  • 768
  • 11
  • 25
1

full code to achieve file upload using autoit tool. u can just copy paste this and u can run, it will work since it is a acti-time demo.

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
import os

def fileUploading():

    driver = webdriver.Firefox()
    driver.implicitly_wait(20)
    wait = WebDriverWait(driver, 10)
    driver.get("https://demo.actitime.com/login.do");
    driver.find_element(By.ID,"username").send_keys("admin")
    driver.find_element(By.NAME, "pwd").send_keys("manager")
    driver.find_element(By.XPATH, "//div[.='Login ']").click()
    wait.until(ec.element_to_be_clickable((By.XPATH, "(//div[@class='popup_menu_icon'])[3]")))
    driver.find_element(By.XPATH, "(//div[@class='popup_menu_icon'])[3]").click()
    wait.until(ec.element_to_be_clickable((By.XPATH, "//a[contains(text(),'Contact actiTIME Support')]")))
    driver.find_element(By.XPATH, "//a[contains(text(),'Contact actiTIME Support')]").click()
    wait.until(ec.element_to_be_clickable((By.XPATH,"//div[@class='dz-default dz-message']")))
    driver.find_element(By.XPATH,"//div[@class='dz-default dz-message']").click()
    os.system("C:\\Users\\mallikar\\Desktop\\screenUpload.exe")
    time.sleep(2000)

fileUploading()

below is the content of autoit code:

WinWaitActive("File Upload")
Send("D:\SoftwareTestingMaterial\UploadFile.txt")
Send("{ENTER}")

download autoIt and autoIt SCITE editor tool. once done install autoit and the open the scite editor and paste the above code and save it with .au3 extension and once saved, right click on the file and select complile script(x64), now .exe file is created.

now use the below code:

os.system("C:\\Users\\mallikar\\Desktop\\screenUpload.exe")
Mallikarjuna B
  • 13
  • 1
  • 1
  • 5
1
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
    driver = webdriver.Firefox()
    driver.get("http://www.example.org")
    def upload_file():
        upload_file = driver.find_element_by_id("paste here id of file which 
        is 
        enter code here`shown in html code...")

       upload_file.send_keys("copy the path of file from your pc with name and 
       paste here...")

if toast message is disappeared within seconds you can use Chropath extension in chrome to find its xpath

This is a pure python code.

GHULAM NABI
  • 498
  • 5
  • 15
1

Instead of using control_send, use control_set_text to resolve inconsistencies present in the string sent to the window. See this link for reference: https://www.autoitscript.com/forum/topic/85929-incorrect-string-being-sent-via-controlsend/

import autoit

autoit.win_wait_active("Open")
autoit.control_set_text("Open", "Edit1", imgPath)
autoit.send("{ENTER}")
Dragon
  • 1,194
  • 17
  • 24
sherlock
  • 15
  • 5
  • this is the best solution i see here. Only the last line might be weak if during execution some other window gets to foreground and autoit.send("{ENTER}") will be send to that windows. the work around is to use autoit.control_click("Open", "Button1") instead. worked perfect for me even when window is in background. – fekiri malek Jan 24 '23 at 18:09
0

I have used below script format to upload the images. This may help you.

   Imagepath=os.path.abspath('.\\folder1\\subfolder2\file1.jpg')
   driver.find_element_by_id("Id of the element").clear()            
   driver.find_element_by_id("Id of the element").send_keys(Imagepath)

if you do not have ID of the object ,then you can use xpath or css selector accordingly.

Tester P
  • 167
  • 1
  • 5
  • 15
0

Using splinter :

browser.attach_file('file_chooser_id',fully_qualified_file_path)

Anjan Dash
  • 194
  • 1
  • 4
0

If you are using service you will get an exception

service = Service('driver_path')
service.start()
driver = webdriver.Remote(service.service_url)
choose_image = driver.find_element(By.ID, 'id')
choose_image.send_keys(os.getcwd()+'/image.jpg')

Exception :

selenium.common.exceptions.WebDriverException: Message: unknown command: unknown command: session/$sessionId/se/file

Working code (suggestion - use id of the element instead of other)

driver=webdriver.Chrome(executable_path=driver_path)
choose_image=driver.find_element(By.ID, 'id')
choose_image.send_keys(os.path.join(os.getcwd(), 'image.jpg'))
Flair
  • 2,609
  • 1
  • 29
  • 41
0

In case you want to upload multiple pictures, you can alter the single image answer as follows:

images = ["/path/to/image1.png", "/path/to/image2.png","/path/to/image3.png"]
drv.find_element_by_id("IdOfInputTypeFile").send_keys("\n".join(images))

Note that the input form should have the multiple attribute set to True.

Saaru Lindestøkke
  • 2,067
  • 1
  • 25
  • 51
0

I post a solution that i consider best. it is a modification on solution by @sherlock (see my comment on that post)

import autoit
    
autoit.win_wait_active("Open")
autoit.control_set_text("Open", "Edit1", imgPath)
autoit.control_click("Open", "Button1")
fekiri malek
  • 354
  • 1
  • 3
  • 14
0

Install these three

sudo apt-get install python3-tk python3-dev
pip install tk
pip install PyAutoGUI

use these two line of code.

pyautogui.write('/home/image.jpg')
pyautogui.press('enter')
Toto
  • 570
  • 4
  • 13
0
from selenium import webdriver
import os
from selenium.webdriver.common.by import By
import time
import pyautogui
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
import autoit
import subprocess

driver = webdriver.Chrome()
driver.get("https://www.imagetotext.io/")
time.sleep(5)

element_present = EC.presence_of_element_located((By.XPATH, "//span[contains(text(),'Browse')]"))
WebDriverWait(driver, 5).until(element_present).click() # This opens the windows file selector

# Activate the file dialog box using AutoIt
autoit.win_activate("Open")

# Call the AutoIt script to handle the file upload dialog
# Path to the AutoIt compiled EXE file
autoit_exe_path = 'script.exe'

# Run the AutoIt script
subprocess.call(autoit_exe_path)

time.sleep(100)