I am trying to use Selenium with Python to find an athlete in a sports competition website. Since the website is very badly written I thought the easiest way to find her was not by searching for the element in HTML, but to simply make the driver press ctrl+F and then type in her name.
This is the url if you want to give it a go: https://www.federdanza.it/images/gare/2019_2020/EXPORT/20210717_padiglione1/6052-coppie_danzestd_senior3(55-60)_as/index.htm
Up to now, I have managed to type into the DuckDuckGo search bar, but I do not understand why I cannot type into the Chrome search bar.
As you can see, the code at the moment is trying to search for "RUG".
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
import time
PATH = "/chromedriver"
driver = webdriver.Chrome(PATH)
driver.get(url)
driver.maximize_window()
time.sleep(10)
#Waiting for the web page to load
action1 = ActionChains(driver)
action2 = ActionChains(driver)
action3 = ActionChains(driver)
action1.key_down(Keys.COMMAND).send_keys('F').key_up(Keys.COMMAND)
action2.send_keys('R').send_keys('U').send_keys('G')
action3.send_keys(Keys.ENTER)
action1.perform()
action2.perform()
action3.perform()
I even asked the program to tell me in Console each time an action has been performed successfully and it seems to work fine, even though there is no response in the browser.
Could it be because I am using a Mac and keys are slightly different? On Windows, the search command is invoked by Ctrl+F while on Mac is invoked by Cmd+F. What else could I try?
Instead of using Actionschains you could try the pyautogui module. Searching a word would look something like this:
import pyautogui
pyautogui.hotkey('ctrl','f')
pyautogui.typewrite('Your keyword')
pyautogui.hotkey('Return')
More information here: https://pyautogui.readthedocs.io/en/latest/
I'm currently attempting to load two extensions into Selenium's ChromeDriver. Ublock Origin and Ghostery. Looking online, the solution for this tends to just be as simple as adding an argument for each extension. However, when I attempt to add these two arguments, it will only load the second defined extension and ignore the first.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
PATH = "C:\Program Files (x86)\chromedriver.exe"
ublock = r'C:\Users\Senuvox\PycharmProjects\Projects\SeleniumExtensions\1.35.2_0'
ghostery = r'C:\Users\Senuvox\PycharmProjects\Projects\SeleniumExtensions\8.5.5_0'
options = Options()
options.add_argument('load-extension=' + ghostery)
options.add_argument('load-extension=' + ublock)
options.add_argument('--ignore-ssl-errors=yes')
options.add_argument('--ignore-certificate-errors')
driver = webdriver.Chrome(PATH, options=options)
driver.create_options()
driver.get("http://www.google.com")
When one runs this script, as stated before, only Ublock will load into the Selenium chrome browser. Similarly, if I swap the order so Ublock is first and Ghostery is second, only Ghostery will load.
Additionally I have attempted to one-line it by adding commas in-between the two extension variables. Unfortunately, this provides an error as add_argument takes only two positional arguments.
Any insights on how I might solve this would be greatly appreciated!
#use .crx file path of extension
options.add_extension('C:\\Users\\ublock-1.35.2_0.crx')
options.add_extension('C:\\Users\\ghostery-8.5.5_0.crx')
useful resource
I am trying to do what the title says, using Python's Selenium Webdriver, with an existing Firefox profile living in <PROFILE-DIR>.
What I've tried
used the options.profile option on the driver:
#!/usr/bin/env python
from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
from selenium.webdriver import Firefox, DesiredCapabilities
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.options import Options
options = Options()
options.profile = '<PROFILE_DIR>'
webdriver = Firefox(options=options)
This copies the existing profile to a temporary location. I can see it works because the new session I start has access to the profile's old cookies, etc. But it is not what I am after: I want to use the profile in-place.
tried to pass the profile as '--profile ' to the args capability: change the code above to
capabilities = DesiredCapabilities.FIREFOX.copy()
capabilities['args'] = '--profile <PROFILE-DIR>'
webdriver = Firefox(desired_capabilities=capabilities)
Nothing doing: viewing the geckodriver.log after closing the session still shows me something like Running command: "/usr/bin/firefox" "--marionette" "-foreground" "-no-remote" "-profile" "/tmp/rust_mozprofileOFKY46", i.e. still using a temporary profile (which is not even a copy of the existing one; the old cookies are not there).
tried the same with capabilities['args'] = ['-profile', '<PROFILE-DIR>'] instead (i.e. a list of strings instead of a single string); same result.
read a bunch of other SO posts, none of which do it. This is mostly because they're specific to Chrome (to whose driver you can apparently pass command-line options; I haven't seen something like this for geckodriver), or because they fall back to copies of existing profiles.
The most relevant answer in this direction implements essentially the same hack I'd thought of, in a pinch:
start the driver with a copy of your existing profile using options.profile as described above;
close the driver instance manually when done (e.g. with a Ctrl+C, or SIGINT) so that the temp-profile directory isn't deleted;
copy over all of the stuff that's left on top of the existing profile, giving you access to whatever leftovers you wanted from the automated session.
This is ugly and feels unnecessary. Besides, geckodriver's failure to remove temporary profiles (which I'd be relying on) is considered a bug..
Surely I'm misunderstanding how to pass those capability options mentioned above, or some such thing. But the docs could do a better job of giving examples.
I've come up with a solution that allows the user to use a Firefox profile in place, by passing the profile path dynamically via an environment variable to Geckodriver.
I start by downloading Geckodriver 0.32.0 and made it so that you simply need to provide the Firefox profile directory via the environment variable FIREFOX_PROFILE_DIR.
The code change is in src/browser.rs, line 88, replacing:
let mut profile = match options.profile {
ProfileType::Named => None,
ProfileType::Path(x) => Some(x),
ProfileType::Temporary => Some(Profile::new(profile_root)?),
};
with:
let mut profile = if let Ok(profile_dir) = std::env::var("FIREFOX_PROFILE_DIR") {
Some(Profile::new_from_path(Path::new(&profile_dir))?)
} else {
match options.profile {
ProfileType::Named => None,
ProfileType::Path(x) => Some(x),
ProfileType::Temporary => Some(Profile::new(profile_root)?),
}
};
You may refer to my Git commit to see the diff against the original Geckodriver code.
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.
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.
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')
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.
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.
You only need to install AutoIt
https://pypi.python.org/pypi/PyAutoIt/0.3 or just "pip install -U pyautoit" through the cmd screen
type "import autoit" on your script page
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")
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
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
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.
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
shell.Sendkeys("C:\text.txt")
shell.Sendkeys("~")
Will resolve the issue
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:
open the inspect and click exactly on the box which you want to
upload the file.
right click on the html code and select xpath full address from copy
sub menu.
paste the root in xpath field in the code.
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")
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.
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}")
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')
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.
Using splinter :
browser.attach_file('file_chooser_id',fully_qualified_file_path)
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'))
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.
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")
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')
I went to Chrome Extension Downloader to snag the .crx file for 'Adblock-Plus_v1.4.1'.
I threw it in the directory I'm working in, and then ran:
from selenium import webdriver
chop = webdriver.ChromeOptions()
chop.add_extension('Adblock-Plus_v1.4.1.crx')
driver = webdriver.Chrome(chrome_options = chop)
It totally acknowledges that it exists, but it gives me what looks like a ChromeDriver.exe style message:
ERROR:extension_error_reporter.cc(56)] Extension error: Package is invalid: 'CRX_PUBLIC_KEY_INVALID'.
Then eventually a webdriver exception:
selenium.common.exceptions.WebDriverException: Message: u'Extension could not be installed'
I am almost 100% sure that there is nothing wrong with my code, because of the fact it puts a ChromeDriver type message first before throwing the exception.
I also tried to pack it myself by going to 'C:\Documents and Settings\\*UserName*\Local Settings\Application Data\Google\Chrome\User Data\Default\Extensions' on chrome://extensions/ with developer mode on, tried to use that .crx that was created and got the exact same error message
I also tried a different way:
chop = webdriver.ChromeOptions()
chop.add_argument('--load_extension=Adblock-Plus_v1.4.1.crx')
driver = webdriver.Chrome(chrome_options = chop)
this doesn't cause an exception or even a Chrome Driver error, but if I manually go to chrome://extensions/ it doesn't say that the extension is loaded...
I'm thinking my problem has to do with the actual .crx file itself. because of the nature of the error message... but then at the same time, I'm not sure because if I spawn a webdriver.Chrome() session, and then manually go to chrome://extensions/ i can physically drag and drop install the same .crx file.
Edit: I realized I didn't actually ask a question so here it is:
What am I doing wrong? Why can't I load this chrome extension? Is it my code, or the .crx file itself?
UPDATE: #Pat Meeker
I've tried this, but im losing something in the translation from java to python
capability = webdriver.DesiredCapabilities.CHROME returns a dictionary that has all my arguments in i, so I'm pretty sure the only part that I need to do is add the arguments.
options = webdriver.ChromeOptions()
options.add_argument('--user-data-dir=C:/Users/USER_NAME/AppData/Local/Google/Chrome/User Data/Default/')
This is what I have right now, and whenever I try to driver = webdriver.Chrome(chrome_options=options) chrome opens up, and it seems to remember its previous position, but NOTHING more, no bookmarks, no extensions no nothing.
Just add this extra line in your program
from selenium.webdriver.chrome.options import Options it will work...
like this
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chop = webdriver.ChromeOptions()
chop.add_extension('Adblock-Plus_v1.4.1.crx')
driver = webdriver.Chrome(chrome_options = chop)
From my skimpy experience the problem is with the load-extesion argument and not your code as I had the same problem with testing an extension that's not from Chrome Web Store.
I managed to solve it by installing the extension with Drag & Drop and using only the --user-data-dir argument.
This worked for me with C# and Chrome 33, I know it sounds flimsy but it works for me for several months now so I hope it'll help.