I have a code that tell Selenium to wait until an element is clickable but for some reason, Selenium doesnt wait but instead, click that element and raise a Not clickable at point (x, y) immediately. Any idea how to fix this ?
x = '//*[#id="arrow-r"]/i'
driver = webdriver.Chrome(path)
driver.get('https://www.inc.com/inc5000/list/2017')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, x)))
driver.find_element_by_xpath(x).click()
EC.element_to_be_clickable check if element is visible and enabled. In terms of visibility it doesn't cover scenario when element is behind other. Maybe your page use something like blockUI widget and click() occurs before the cover disappears. You can check if element is truly clickable by enriching EC.element_to_be_clickable((By.XPATH, x)) check with assertion that ensure element is not behind by other. In my projects I use implementation as below:
static bool IsElementClickable(this RemoteWebDriver driver, IWebElement element)
{
return (bool)driver.ExecuteScript(#"
(function(element){
var rec = element.getBoundingClientRect();
var elementAtPosition = document.elementFromPoint(rec.left+rec.width/2, rec.top+rec.height/2);
return element == elementAtPosition || element.contains(elementAtPosition);
})(arguments[0]);
", element);
}
This code is in C# but I'm sure you can easily translate into your programming language of choice.
UPDATE:
I wrote a blog post about problems related to clicking with selenium framework https://cezarypiatek.github.io/post/why-click-with-selenium-so-hard/
Here is a link to the 'waiting' section for the Python Selenium docs: Click here
Wait will be like:
element = WebDriverWait(driver, 10).until(
EC.visibility_of((By.XPATH, "Your xpath"))
)
element.click();
Related
I have been pained by a load more button for a while. I'm looking to create a loop where I click "load more" on the skills section of Linkedin pages. However, this button is just not consistently being clicked.
I was under the impression that the issue was that the element was not visible on the page. So, I have a segmented scroll, which continues moving down the page until the element is found. But what's baffling is that even though the page is now moving to the right place, the element is not being clicked. No error is being thrown.
I've tried nearly every version of the element location (xpath, class name, css selector, full xpath). Why would the button not be clicked, if it is visible on the page?
Relevant Code:
##log into Linkedin
linkedin_urls=['https://www.linkedin.com/in/julie-migliacci-revent/']
ChromeOptions = webdriver.ChromeOptions()
driver = webdriver.Chrome('C:\\Users\\Root\\Downloads\\chromedriver.exe')
driver.get('https://www.linkedin.com/login?fromSignIn=true&trk=guest_homepage-basic_nav-header-signin')
driver.maximize_window()
WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.NAME, "session_key"))).send_keys("EMAIL")
WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.NAME, "session_password"))).send_keys("PASSWORD")
WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//button[#class='btn__primary--large from__button--floating']"))).click()
linkedin_urls=['https://www.linkedin.com/in/julie-migliacci-revent/', 'https://www.linkedin.com/in/kathleen-meyers-126a7931']
for linkedin_url in linkedin_urls:
driver.get(linkedin_url)
looking_for_element = True
ldmore = ''
while looking_for_element:
elements = driver.find_elements_by_xpath('/html/body/div[7]/div[3]/div/div/div/div/div[2]/main/div[2]/div[6]/div/section/div[2]/button/span[1]')
if len(elements) > 0:
ldmore = elements[0]
ldmore.click()
looking_for_element = False
else:
global_copyright = driver.find_elements_by_css_selector('#globalfooter-copyright')
if len(global_copyright) > 0:
looking_for_element = False
else:
body = driver.find_element_by_css_selector('body')
sleep(5)
body.send_keys(Keys.PAGE_DOWN)
I've not seen a discussion on SO about element issues when the underlying solution is not visibility. The code is designed to stop once the element is located -- and is performing this correctly. But it just isn't clicking on the element. I'm not sure why this is.
Locations I've tried:
absolute xpath:
driver.find_element_by_xpath('/html/body/div[7]/div[3]/div/div/div/div/div[2]/main/div[2]/div[6]/div/section/div[2]/button/span[1]').click()
relative xpath:
//span[contains(text(),'Show more')]
class name:
pv-profile-section__card-action-bar pv-skills-section__additional-skills artdeco-container-card-action-bar artdeco-button artdeco-button--tertiary artdeco-button--3 artdeco-button--fluid" aria-controls="skill-categories-expanded
css:
body.render-mode-BIGPIPE.nav-v2.theme.theme--classic.ember-application.boot-complete.icons-loaded:nth-child(2) div.application-outlet:nth-child(77) div.authentication-outlet:nth-child(3) div.extended div.body div.pv-profile-wrapper.pv-profile-wrapper--below-nav div.self-focused.ember-view div.pv-content.profile-view-grid.neptune-grid.two-column.ghost-animate-in main.core-rail div.profile-detail div.pv-deferred-area.ember-view:nth-child(6) div.pv-deferred-area__content section.pv-profile-section.pv-skill-categories-section.artdeco-container-card.ember-view div.ember-view > button.pv-profile-section__card-action-bar.pv-skills-section__additional-skills.artdeco-container-card-action-bar.artdeco-button.artdeco-button--tertiary.artdeco-button--3.artdeco-button--fluid
UPDATE:
Tried the JS force, it clicked! But threw up the error: selenium.common.exceptions.WebDriverException: Message: unknown error: Cannot read property 'click' of null
if len(elements) > 0:
ldmore = elements[0]
ldmorebtn = driver.find_element_by_xpath('/html/body/div[7]/div[3]/div/div/div/div/div[2]/main/div[2]/div[6]/div/section/div[2]/button/span[1]').click()
#driver.execute_script("arguments[0].checked = true;", ldmore)
driver.execute_script("arguments[0].click();", ldmore)
The suggestion by #Datanovice to use javascript to force a click worked like a charm. Initially, when I had tried to adapt the solution, I received the error selenium.common.exceptions.WebDriverException: Message: unknown error: Cannot read property 'click' of null.
This error was because I had been using EC.element_to_be_clickable. Instead, when I paired the java method with EC.visibility_of_element_located, the click consistently worked.
The code:
ldmore = WebDriverWait(driver, 30).until(EC.visibility_of_element_located((By.XPATH,'xpath')))
driver.execute_script("arguments[0].click();", ldmore)
My Python Selenium can't click target element, instead seem click element behind target element?
I try to click, or enter text in 'drop-down meun', but I find that I am result in clicking element behind this 'drop-down. I know this is element behind it, because there is advistering area behind, and the result top-up showing the same advistering material. Here is my code:
# info for login
my_email = 'my_email'
my_passcode = 'my_passcode'
email_url = r'https://www.gmx.com/#.1559516-header-navlogin2-1'
# start driver and open url
driver = webdriver.Chrome(chrome_path)
driver.get(email_url)
# input email account
xpath = r'//*[#id="login-email"]'
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, xpath)))
target = driver.find_element_by_xpath(xpath)
actions = ActionChains(driver)
actions.move_to_element(target).perform()
actions.click().send_keys(my_email).perform()
# input passcode and hit 'enter' to login
xpath = r'//input[#id="login-password"]'
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, xpath)))
target = driver.find_element_by_xpath(xpath)
actions = ActionChains(driver)
actions.move_to_element(target).perform()
actions.click().send_keys(my_passcode).send_keys(Keys.ENTER).perform()
It happens to me for some other site when the site appear to have 'two layers' (not sure if I am using the right word). I can process anything on top layer, and only result in activate anything behind it. Many thank when provide solution!!
You don't need to use this ActionChains class, all you need to do can be done using WebElement.send_keys() and WebElement.click()
You don't need to re-find the element after using WebDriverWait as it returns the WebElement in case of success
I fail to see clickign on login button anywhere in your script, you can locate the relevant button using XPath contains() function like:
xpath = r'//button[contains(#class,"login-submit")]'
and then just call click() function on the resulting variable
Example suggested code:
You don't need to use this ActionChains class, all you need to do can be done using WebElement.send_keys() and WebElement.click()
You don't need to re-find the element after using WebDriverWait as it returns the WebElement in case of success
I fail to see clickign on login button anywhere in your script, you can locate the relevant button using XPath contains() function like:
xpath = r'//button[contains(#class,"login-submit")]'
and then just call click() function on the resulting variable
Example suggested code:
# input email account
xpath = r'//*[#id="login-email"]'
target = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, xpath)))
target.send_keys(my_email)
# input passcode and hit 'enter' to login
xpath = r'//input[#id="login-password"]'
target = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, xpath)))
target.send_keys(my_passcode)
xpath = r'//button[contains(#class,"login-submit")]'
target = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, xpath)))
target.click()
I have this code:
driver.switch_to.window(window_after)
try:
myElem = WebDriverWait(driver, delay).until(EC.presence_of_element_located((By.NAME, '_eventId_confirmed')))
print ("Page 2 is ready!")
except TimeoutException:
print ("Loading took too much time!")
btn = driver.find_element_by_name('_eventId_confirmed')
btn.click()
as you can see I first switch window and then check for an element, get that element (a button) and finally try to click on said button. This works maybe 2 out of 3 times but ever so often does it fail with this error message
selenium.common.exceptions.ElementNotInteractableException: Message: Element <button class="btn" name="_eventId_confirmed"> could not be scrolled into view
When visually looking at the flow when it is executing everything seems fine (my first guess was that the window switch didn't work as expected) and the browser ends up in the expected state where I am able to manually click this button. Interestingly enough, there is no timeout or similar when this error occurs, it happens instantly during execution.
Any ideas what's going on here?
This problem usually arises when the element you are trying to click is present on the page but it is not fully visible and the point where selenium tries to click is not visible.
In this case, you can use javascript to click on the element, which actually operates directly on the html structure of the page.
You can use it like:
element = driver.find_element_by_name("_eventId_confirmed")
driver.execute_script("arguments[0].click();", element)
As your final step is to invoke click() on the desired element, so instead of using the expected_conditions as presence_of_element_located() you need to use element_to_be_clickable() as follows:
try:
myElem = WebDriverWait(driver, delay).until(EC.element_to_be_clickable((By.NAME, '_eventId_confirmed')))
Here are the 2 options.
Using selenium location_once_scrolled_into_view method:
btn.location_once_scrolled_into_view
Using Javascript:
driver.execute_script("arguments[0].scrollIntoView();",btn)
Sample Code:
url = "https://stackoverflow.com/questions/55228646/python-selenium-cant-sometimes-scroll-element-into-view/55228932? noredirect=1#comment97192621_55228932"
driver.get(url)
element = driver.find_element_by_xpath("//a[.='Contact Us']")
element.location_once_scrolled_into_view
time.sleep(1)
driver.find_element_by_xpath("//p[.='active']").location_once_scrolled_into_view
driver.execute_script("arguments[0].scrollIntoView();",element)
I have a web page which loads content dynamically and while page loads, there is spinning wheel, I already found solution to grab content loaded immediately on page, but seems i can't find solution to grab content loaded later in dom.
What i can think of is to find element with specific class of that wheel spinning, and wait for it to change, once it's changed, than it means content is loaded in dom.
I am using Selenium with Firefox webdriver on Ubuntu.
Here is the class i am looking to monitor:
<div class="wheel spinning"></div>
Once content is loaded, wheel stop spinning and class is changed to:
<div class="wheel"></div>
Anyone find solution to find and monitor class="wheel spinning" and once it's changed to class="wheel" to continue to grab data.
Edit:
The XPATH actually solved one part of solution, here's part of code
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "//*[#class='wheel']))
)
title = driver.find_element_by_xpath('/html/body/div[1]/div[1]/div[3]')
print(title.text)
But if element don't appear within 10 seconds it error's out, now to find a way to retry again and again until element is present on page.
Is there a difference in use presence_of_element_located((By.XPATH)) and find_element_by_xpath
You can wait for the class value to change. For example:
from selenium.webdriver.support.ui import WebDriverWait
# Wait longer than 10 seconds since you're getting occasional timeout
el = WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.XPATH, "//*[#class='wheel']")))
wait = WebDriverWait(driver, 10)
wait.until(lambda d: 'spinning' not in el.get_attribute('class'))
The until method passes the driver to the method given, so you can make your own expected condition pretty easily. The above uses an anonymous lambda function but you could also use a closure or a anything callable that takes in an argument (the ExpectedConditions library is just a set of callable classes). Here is the same with a closure:
from selenium.webdriver.support.ui import WebDriverWait
# Wait longer than 10 seconds since you're getting occasional timeout
el = WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.XPATH, "//*[#class='wheel']")))
def wait_not_spinning(driver):
return 'spinning' not in el.get_attribute('class')
wait = WebDriverWait(driver, 10)
wait.until(wait_not_spinning)
#LucasTierney's answer was in the right direction. However I still feel the solution can be optimized as follows:
As the wheel is visible, instead of presence_of_element_located() method you need to use visibility_of_element_located() method.
The node:
<div class="wheel spinning"></div>
Can't be located through the XPath containing a single class i.e. only wheel as in:
el = WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.XPATH, "//*[#class='wheel']")))
Instead you can use either of the Locator Strategies:
cssSelector:
el = WebDriverWait(driver, 30).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.wheel.spinning")))
WebDriverWait(driver, 10).until(lambda d: 'spinning' not in el.get_attribute('class'))
xpath:
el = WebDriverWait(driver, 30).until(EC.visibility_of_element_located((By.XPATH, "//div[#class='wheel spinning']")))
WebDriverWait(driver, 10).until(lambda d: 'spinning' not in el.get_attribute('class'))
I am unable to close a popup box with Selenium. Below is the code I have written, it returns an exception. Please see the code below.
driver = webdriver.Chrome()
driver.get("https://www.google.com/webhp#q=home+depot+san+francisco&lrd=0x808f7c5c63124c7b:0x32c19e9988b2aa90,1,")
driver.find_element_by_xpath('//div[#class="_wzh"]').click()
# selenium.common.exceptions.ElementNotVisibleException: Message: element not visible
Thanks,
It take some time to open your popup. So you need to wait for few seconds until the popup opens and close button get visible.
User Explicitwait condition until visibility of element like below :
element = WebDriverWait(driver, 60).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, "div>._wzh"))
)
element.click()
Instead of trying to click on element, you should use the built-in support.
Following should work.
alert = driver.switch_to_alert()
alert.accept
Docs
this is because the element is present on an <iframe> tag; so first you need to switch to iframe and then interact with the element:
driver.switch_to.frame driver.find_element_by_css(' #gsr > iframe')
then click on the element:
driver.find_element_by_xpath('//div[#class="_wzh"]').click()