Using the Python version of Selenium, is it possible to click some element in the DOM and to specify the coordinates where you want to click it?
The Java version has the method clickAt, which actually does exactly what I am looking for, but can't find the equivalent in Python.
This should do it! Namely you need to use action chains from webdriver. Once you have an instance of that, you simply register a bunch of actions and then call perform() to perform them.
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("http://www.google.com")
el=driver.find_elements_by_xpath("//button[contains(string(), 'Lucky')]")[0]
action = webdriver.common.action_chains.ActionChains(driver)
action.move_to_element_with_offset(el, 5, 5)
action.click()
action.perform()
This will move the mouse 5 pixels down and 5 pixels right from the upper-left corner of the button I feel lucky. Then it will click().
Notice that you must use perform(). Else nothing will happen.
The reason you are getting confused is clickAt is an old v1 (Selenium RC) method.
WebDriver has a slightly different concept, of 'Actions'.
Specifically, the 'Actions' builder for the Python bindings live here.
The idea of the clickAt command is to click at a certain position relative to a particular element.
The same is achievable within the WebDriver, using the 'Actions' builder.
Hopefully this updated documentation can help.
You can perform the task with the Action chains in the python specially with Edge browser:
from selenium.webdriver import ActionChains
actionChains = ActionChains(driver)
button_xpath = '//xapth...'
button = driver.find_element_by_xpath(button_xpath)
actionChains.move_to_element(button).click().perform()
But sometimes Action chain does not finds the DOM element. Hence better option to use execute scipt in following way:
button_xpath = '//xapth...'
button = driver.find_element_by_xpath(button_xpath)
driver.execute_script("arguments[0].click();", button)
I've not personally used this method, but looking through the source code of selenium.py I've found the following methods that look like they'd do what you want - They look to wrap clickAt:
def click_at(self,locator,coordString):
"""
Clicks on a link, button, checkbox or radio button. If the click action
causes a new page to load (like a link usually does), call
waitForPageToLoad.
'locator' is an element locator
'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator.
"""
self.do_command("clickAt", [locator,coordString,])
def double_click_at(self,locator,coordString):
"""
Doubleclicks on a link, button, checkbox or radio button. If the action
causes a new page to load (like a link usually does), call
waitForPageToLoad.
'locator' is an element locator
'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator.
"""
self.do_command("doubleClickAt", [locator,coordString,])
They appear in the selenium object and here is their online API documentation.
Related
My goal is to get an element within a dropdown menu that needs to be clicked in order to appear using python selenium. Also, it seems that before the click, hovering is necessary.
I tried to click the dropdown menu like this:
element = wait().until(EC.presence_of_element_located((By.CLASS_NAME, "c-topmenu c-topmenu--create c-topmenu--userbar tw-inline-flex")))
element.click()
def wait():
return WebDriverWait(driver, 30)
And tried to use hovering:
Hover = ActionChains(driver).move_to_element(element)
Hover.click().build().perform()
Still, I get a TimeoutException and can't figure out a solution.
The website komoot looks like this before clicking the dropdown menu:
The website komoot looks like this after expanding it:
Ok here is how i was able to get this working.
after the login i grapped the wrapper element from the link with:
more_menu_wrapper = driver.find_element_by_css_selector("div[data-test-id='more_menu']")
after that i could click the desired element with:
more_menu_wrapper.find_element_by_tag_name("a").click()
You are using a wrong locator.
In case of multiple class names you should use css_selector or XPath, not by class name.
Also, here you have an unique attribute of data-test-id, you should use it.
Also, you should wait for element visibility or clickability, not just for element presence.
So your code could be:
element = wait().until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div[data-test-id='more_menu']")))
I am trying to automate a task which can save me thousands of clicks.
I searched a bit for available modules in Python and I have selected to work with Selenium.
I installed Firefox drivers and did some progress but I am stuck for a long time. I finally gave up, opened a Stack Overflow account and wanted to bring this problem into this helpful medium.
My code can successfully do some clicks, but I could not make the code click a button like element. I have to click such items so that page opens some new elements. (Hopefully I am going to click on these new elements to save some excels files automatically).
Here is the part which works as expected:
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time
browser = webdriver.Firefox()
url = "https://www.tbb.org.tr/tr/bankacilik/banka-ve-sektor-bilgileri/istatistiki-raporlar/59"
browser.get(url)
time.sleep(2)
bank_reports_element_xpath = "//*[#title= 'Tüm Raporlar']"
bank_reports_element = browser.find_element_by_xpath(bank_reports_element_xpath)
bank_reports_element.click()
time.sleep(2)
second_item = "//div[#data-catid = '52']"
finance_tables_element = browser.find_element_by_xpath(second_item)
finance_tables_element.click()
years_item = "//div[#class = 'years']"
years_element = finance_tables_element.find_element_by_xpath(years_item)
year_elements = years_element.find_elements_by_xpath("a")
There I would like to click on the years.
a screenshot of the years that I can't click using Selenium
As an example, I get the element related to year 2004.
year2004 = year_elements[2]
Issuing a year2004.click() command gives an ElementNotInteractableException exception.
year2004.click() # ElementNotInteractableException: Element could not be scrolled into view
Based on searching similar posts, I tried the following (executing the click via javascript). I got no error but it does not do anything. When I click the year2004 button with mouse, a list pops-up in the page. But when I run the below code, no list pops up in the page.
browser.implicitly_wait(4)
browser.execute_script("arguments[0].scrollIntoView();", year2004)
browser.execute_script("arguments[0].click()", year2004)
I tried also the following code. I get "TypeError: rect is undefined"
browser.implicitly_wait(4)
action = ActionChains(browser)
action.move_to_element(year2004) # gives: TypeError: rect is undefined
action.click(on_element = year2004) # gives: TypeError: rect is undefined
action.perform()
I tried using Chrome Driver and got similar results. The errors definitions were not exactly the same. Instead of the above "rect is undefined" error, Chrome error is like: "Javascript error: Failed to execute 'elementsFromPoints' on 'Document': Provided double value is non-finite"
I don't know if it is relevant but year2004.location dictionary has a 0 value for "x".
I would appreciate any answer,
Keep safe
Use this xpath will give you all the elements of year in 52 category
//div[#data-catid='52']/descendant-or-self::*/div[#class='years']/child::a
for scrolling try
browser.send_keys(Keys.PAGE_DOWN)
I checked manually and page down button is working for me press it twice for desire element
I developed a selenium script, which makes automatic comments in facebook groups.
It works relatively good, but it does not execute the click() method if the targeted element is not visible on the browser.
As a working around I'm using the execute_script("window.scrollTo(x,y";), method, but it's not ideal script. The piece of code that must be improved is the following:
text_box = driver.find_element_by_class_name("UFIAddCommentInput")
try:
driver.execute_script("window.scrollTo(100, 0);")
text_box.click()
except:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
text_box.click()
element = driver.switch_to.active_element
element.send_keys(frase)
element.send_keys(Keys.RETURN)
It first tries for the element on the top of the page, and, if does not get to execute click(), it tries at the bottom.
However, there is a more effective way to scroll at the element found by the find_element_by_class_namemethod?
You can try
text_box.location_once_scrolled_into_view
text_box.click()
to scroll page down right to required element and click it
I am working with selenium (python) and I would like for it to click on a button. The code goes something like this:
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('my_url')
try:
driver.find_element_by_partial_link_text('Mais').click()
except:
pass
Nothing at all happens. After inspecting the source, and I am pretty sure this is the element I want to find:
<input class="ksb _kvc" value="Mais resultados" id="smb" data-lt="Carregando..." jsaction="str.smr" data-ved="0ahUKEwjPtK6Fwv3PAhVGI5AKHTkSDVsQxdoBCE8" type="button" />
Have you tried
driver.find_element_by_id('smb').click()
Rather than
driver.find_element_by_partial_link_text('Mais').click()
I suspect nothing happens because an exception is thrown in your original code if the find fails.
When attempting to locate elements I would usually use id/name as these are normally unique. For a full list see selenium-python.readthedocs.io/locating-elements.html
You are having issue clicking the button because you are using driver.find_element_by_partial_link_text() which is only good for finding link (anchor elements) by its partial text, and performing actions on it.
You should rely on the other find_element_by_xxxx() methods which allow us to find by element ID, Name, XPath, CSS selector, or Class name.
Refer the documentation on locating elements at : http://selenium-python.readthedocs.io/locating-elements.html
I'm using Selenium with Python3 to automate entering data into a website.
I have tried looking everywhere for how to deal with selecting an element by class if there is more than one but I can't figure out how to select the accordion-toggle[1]. Nothing happens on selenium but it works fine on any browser. Also, is there any way to just use the regular javascript or jquery commands?:
accordion=find_element_by_class("accordion-toggle"[1])
accordion.click()
#otheraccordion=find_element_by_css_selector("#AdvancedAddress > div.accordion-heading.in > div.accordion-toggle > span.accordionExpandCollapse")
#otheraccordion.click()
StreetNameField=driver.find_element_by_id("Advanced_FindMyParcel_PropertyStreetName")
StreetNameField.send_keys("Sherman")
ZipField=driver.find_element_by_id("Advanced_FindMyParcel_PropertyZip")
ZipField.send_keys("90201")
ZipButton=driver.find_element_by_id("btnSearchFindMyParcels")
ZipButton.click()
You actually can use document.getElementsByClassName() through execute_script() call:
driver.execute_script("document.getElementsByClassName('accordion-toggle')[0].click();")
But I would not go down to executing javascript for such a simple task. Easier to locate the element using find_element_by_class_name():
accordion = driver.find_element_by_class_name('accordion-toggle')
accordion.click()
You are looking for find_element(s)_by_css_selector - reference here - use the css prefix '.classname` to indicate the class.
e.g. to find
<div class='theClass'>
driver.find_elements_by_css_selector('.theClass')
You can also use the By syntax:
driver.find_elements(By.CSS_SELECTOR, '.theClass')
Edit
It seems the problem may be more to Clicking the element, rather than finding it.
Ensure the element is visible
For Chrome, you may need to mimic hovering the mouse over the element before clicking this - see Actions / ActionChains MoveToElement to hover over the element.
For IE, you may need to ensure the browser / frame gets the focus, prior to the element Click - you may need to apply a hack like one of these.
In addition to #alecxe response, I would also suggest using the function find_elements_by_class_name instead of find_element_by_class_name in case there are multiple elements with the same class name.
accordion = driver.find_elements_by_class_name('accordion-toggle')[1] # Selects second element
accordion.click()
Using find_element_by_class_name will return only the first element with that class name.