Button click using Selenium not actionable - python

I am trying to fill in a registration form and click submit. But Selenium says the Registration button is not actionable. I have tried using actionchains and a couple of other techniques but generally get the same error.
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
My code...
driver.get('https://discover.workato.com/automate-2022/p/1?utm_source=Automate+2022&utm_medium=employee+referral&utm_campaign=MCoblentz')
time.sleep(3)
first_name = driver.find_element_by_xpath('//*[#id="FirstName"]')
first_name.send_keys(line[1])
skipping a few more fields to the button click (and neither the by class name or the xpath work)...
Button = driver.find_element(By.class name("mktoButtonWrap"))
# Button = driver.find_element_by_xpath('//*[#id="mktoForm_3468"]/div[17]/span')
Button.click()
For the life of me, I can't figure out:
Why the button is not actionable and what I need to do to click it. (Major problem)
Why Python won't run with the following find_element line (minor annoyance)
Button = driver.find_element(By.xpath('//*[#id="mktoForm_3468"]/div[17]/span')
Python is throwing an error that
'AttributeError: type object 'By' has no attribute 'xpath'
But I'm initializing with:
from selenium.webdriver.common.by import By

Your syntax is incorrect. It should be:
Button = driver.find_element(By.XPATH, '//*[#id="mktoForm_3468"]/div[17]/span')
If you import By correctly (from selenium.webdriver.common.by import By), your IDE should autocorrect and show correct options:

You need to consider a couple of things here as follows:
Instead of:
Button = driver.find_element(By.class name("mktoButtonWrap"))
It should have been:
Button = driver.find_element(By.CLASS_NAME, "mktoButtonWrap")
Similarly,
Button = driver.find_element(By.XPATH, '//*[#id="mktoForm_3468"]/div[17]/span')
Further, this error message...
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
indicates that the desired element is not interactable.
Solution
To click on Register you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following locator strategies:
Using XPATH:
driver.get("https://discover.workato.com/automate-2022/p/1?utm_source=Automate+2022&utm_medium=employee+referral&utm_campaign=MCoblentz")
driver.execute_script("arguments[0].click();", WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[#class='mktoButton' and text()='Register']"))))
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

Related

Build XPATH expression to get and click button element

I'm building a scraper with selenium, and I got it up and running except for one data field I'm missing. I need to first push a button, then get the value. But I haven't been able to push the button, because I can't seem to build the correct xpath expression to get it with selenium,
The url is this one: https://www.ikea.com/mx/es/p/kallax-estante-blanco-80275887/
And I need to click the button "Medidas" (scroll halfway through the page, right between "Detalles del producto" and "Productos similares") to open a side panel and get the info I need.
But so far, I haven't been able to set the correct XPATH expression for the button.
I tried with
driver.find_element_by_xpath(
"//button[#class='range-revamp-chunky-header']"
).click()
But this way it clicked the first button ("Detalles del producto")
Also tried with something like
driver.find_element_by_xpath(
"//button[#class='range-revamp-chunky-header' AND #text='Medidas']"
).click()
But I haven't been able to make it work, I just got this error:
Message: no such element: Unable to locate element: {"method":"xpath","selector":"//button[#class='range-revamp-chunky-header' and #text='Medidas']"}
By the way, the list of buttons is dynamic... sometimes, there can be 1, 2, 3 or 4 buttons with the same class, only difference I can see is the text of the button, so getting always the 2nd button with that class (like in the URL provided) won't always work.
To click on the element with text as Medidas you can use the following Locator Strategy:
Using xpath:
driver.find_element(By.XPATH, "//span[text()='Medidas']").click()
Ideally you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategy:
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//*[contains(., 'login or register')]"))).click()
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

Click on ember.js enabled element using Selenium

I am trying to click on the following button on a linkedin page using selenium:
<button id="ember607" class="share-actions__primary-action artdeco-button artdeco-button--2 artdeco-button--primary ember-view" data-control-name="share.post"><!---->
<span class="artdeco-button__text">
Post
</span></button>
I have tried to use:
driver.find_element_by_id, but the id of the button seems to keep changing number
driver.find_element_by_xpath, but this contains the button number, so also fails
driver.find_element_by_class_name('share-actions__primary-action artdeco-button artdeco-button--2 artdeco-button--primary ember-view'), this fails even though the class name is correct ?
Basically, all methods generate the same error message:
Exception has occurred: NoSuchElementException
Message: no such element: Unable to locate element:{[*the_error_is_here*]}
I have also tried the xpath contains() method, but this does not find the button.
What would be the correct way to click on this button please ?
I am using python version 3.9 on windows with driver = webdriver.Chrome
The element is an Ember.js enabled element. So to click() on the element with text as Post you can use either of the following Locator Strategies:
Using css_selector:
driver.find_element_by_css_selector("button.share-actions__primary-action[data-control-name='share.post']>span.artdeco-button__text").click()
Using xpath:
driver.find_element_by_xpath("//button[contains(#class, 'share-actions__primary-action') and #data-control-name='share.post']/span[#class='artdeco-button__text' and contains(., 'Post')]").click()
Ideally, to click on the element you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.share-actions__primary-action[data-control-name='share.post']>span.artdeco-button__text"))).click()
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[contains(#class, 'share-actions__primary-action') and #data-control-name='share.post']/span[contains(., 'Post')]"))).click()
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
References
You can find a couple of relevant detailed discussions in:
Selenium - Finding element based on ember
Automate Ember.js application using Selenium when object properties are changed at run-time
Ember: Best practices with Selenium to make integration tests in browser
Ember dropdown selenium xpath
Sometimes there are problems with buttons that are not clickable at the moment.
Try this:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
wait = WebDriverWait(driver, 10)
button = wait.until(EC.element_to_be_clickable((By.XPATH, '[YOUR X_PATH TO THE BUTTON]')))
driver.execute_script("arguments[0].click()", button)
It's not the cleanest way to click any Button with selenium, but for me this method works mostly everytime.
//button[#class="share-actions__primary-action artdeco-button artdeco-button--2 artdeco-button--primary ember-view"].
Or
//button[contains(#id,'ember')]
Find the span with Post and click it's button tag.
//span[contains(text(), 'Post')]/parent::button
By xpath this should work:
//button/span[contains(text(), "Post")]
Combine it with a wait for the element:
button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//button/span[contains(text(), "Post")]"))
)
The problem with your by class selectors is the multiple class names. See this question: How to get elements with multiple classes for more details on how to overcome that.

No such element error while clicking on Tinder Log in button

I'm trying to learn how to interact with the internet with python, and followed a tutorial I found on how to make a bot that interacts with tinder. I am able to get a chrome window up, and it can go to the website, but I run into issues when I try to click the login button. Here is the code I used(I imported webdriver from selenium, and sleep from time, but it wouldn't transfer here):
class tinderAI():
def __init__(self):
self.driver = webdriver.Chrome()
def login(self):
self.driver.get('https://tinder.com')
sleep(2)
fb_btn = self.driver.find_element_by_xpath('//*[#id="modal-manager"]/div/div/div/div/div[3]/div[2]/button')
fb_btn.click()
The error code I get after using this code is:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[#id="modal-manager"]/div/div/div/div/div[3]/div[2]/button"}
Any help in resolving the issue would be appreciated. Thanks!
As per your code trials the locator:
//*[#id="modal-manager"]/div/div/div/div/div[3]/div[2]/button
represents the button with text as Log in with Facebook and to invoke click() on the element you need to induce WebDriverWait for the element_to_be_clickable() reaching till the child <span> and you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type = 'button'][aria-label = 'Log in with Facebook'] span"))).click()
Using XPATH:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//button[#type = 'button' and #aria-label = 'Log in with Facebook']//span"))).click()
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
Browser Snapshot:
Reference
You can find a detailed relevant discussion in:
Selenium “selenium.common.exceptions.NoSuchElementException” when using Chrome

Filling webform with selenium, how to click button that is only enabled for certain conditions

I am trying to automatically fill in the form in this website using selenium with python:
https://breast.predict.nhs.uk/tool
I can fill in all the boxes except the "micrometastases only". If I try to click this one in the way I've filled in the others, i.e.:
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
elem = driver.find_element_by_xpath("//*[#id=\"app\"]/div/div/div[3]/div/div/div/div/div[2]/form/div[4]/div[2]/div/div/div[3]/div/div/div/div/button[1]")
elem.click()
I get the following error:
selenium.common.exceptions.NoSuchElementException: Message: no such element:
Unable to locate element: {"method":"xpath","selector":"//*[#id="app"]/div/div/div[3]
/div/div/div/div/div[2]/form/div[4]/div[2]/div/div/div[3]/div/div/div/div/button[1]"}
I believe this is because the micrometastases button only becomes available if/when positive nodes = 1.
In order to try to fix this, I looked at using explicit waiting, in the following way:
element = WebDriverWait(driver, 20).until(ec.element_to_be_clickable((By.XPATH, "//*[#id=\"app\"]/div/div/div[3]/div/div/div/div/div[2]/form/div[4]/div[2]/div/div/div[3]/div/div/div/div/button[1]")))
element.click()
This outputs the following error:
raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message:
What would be the right way to click this button? Any help is appreciated.
Thanks!
Use WebDriverWait and element_to_be_clickable() and following xpath option.
driver.get("https://breast.predict.nhs.uk/tool")
WebDriverWait(driver,20).until(EC.element_to_be_clickable((By.ID,"nodes"))).send_keys('1')
WebDriverWait(driver,20).until(EC.element_to_be_clickable((By.XPATH,"//button[#class='btn btn-default btn-sm custom' and text()='Yes']"))).click()
Apologies, the button only becomes enabled after filling in the previous value and clicking somewhere else on the website. After changing that it worked perfectly.

How to click on the button when the textContext contains leading and trailing white-space characters?

I'm trying to click on the following button using Selenium with python:
<button type="submit" tabindex="4" id="sbmt" name="_eventId_proceed">
Einloggen
</button>
This is just a simple button which looks like this:
Code:
driver.find_element_by_id('sbmt').click()
This results in the following exception:
selenium.common.exceptions.ElementNotInteractableException: Message:
Element <button id="sbmt" name="_eventId_proceed" type="submit">
could not be scrolledinto view
So, I tried scrolling to the element using ActionChains(driver).move_to_element(driver.find_elements_by_id('sbmt')[1]).perform() before clicking the button.
(Accessing the second element with [1] because the first would result in selenium.common.exceptions.WebDriverException: Message: TypeError: rect is undefined exception.).
Then I used
wait = WebDriverWait(driver, 5)
submit_btn = wait.until(EC.element_to_be_clickable((By.ID, 'sbmt')))
in order to wait for the button to be clickable. None of this helped.
I also used driver.find_element_by_xpath and others, I tested it with Firefox and Chrome.
How can I click on the button without getting an exception?
Any help would be greatly appreciated
To invoke click() on the element you need to first use WebDriverWait with expected_conditions for the element to be clickable and you can use the following solution:
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[#id='sbmt' and normalize-space()='Einloggen']"))).click()
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

Categories