Confirm if link is disabled selenium/Python - python

The below code finds the correct link from an unordered list in a browser, however the EC.element_to_be_clickable function doesn't work because if the link wasn't clickable, it will require the browser to be refreshed (to check again).
Instead, is there any way for the link to be checked if it is disabled (and click() if it isn't? The link will come in one of the below formats
<a class="Button disabled">Purchase</a>
<a class="Button">Purchase</a>
Code below
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
try:
if len(driver.find_elements(By.XPATH, "//span[text()='$30.00']/../following-sibling::div/a[text()='Purchase']")) > 0:
print("Found, now attempting to click link")
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='$30.00']/../following-sibling::div/a[text()='Purchase']"))).click()

To check if a link is disabled, ie. if its class contains 'disabled', just look for it in its class:
try:
if len(driver.find_elements(By.XPATH, "//span[text()='$30.00']/../following-sibling::div/a[text()='Purchase']")) > 0:
elem = driver.find_element(By.XPATH, "//span[text()='$30.00']/../following-sibling::div/a[text()='Purchase']")
print("Found, now attempting to click link")
if "disabled" in elem.get_attribute("class"):
print("Link disabled! Refreshing page.")
driver.refresh()
else:
elem.click()

Related

Selecting button in Selenium python using web driver

Can anyone please let me know how to correctly click on the button using Selenium webdriver?
I have the following html element I want to click:
<button type="button" class="btn button_primary" data-bind="click: $parent.handleSsoLogin.bind($parent)"> Sign In
</button>
I am trying to use WebDriver with python but it doesn't find the element. Please advise how to address it?
from xml.dom.expatbuilder import InternalSubsetExtractor
from selenium.webdriver.common.by import By
import time
# imports parts of interest
from selenium import webdriver
# controlling the chrome browser
driver = webdriver.Chrome()
link=xxxxx
driver.get(link2)
# login = driver.find_element(By.LINK_TEXT,"Login")
time.sleep(10)
# login.click()
driver.find_element(By.ID,'CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll')
time.sleep(10)
login=driver.find_element(By.CSS_SELECTOR("<button type="buttonclass="btn button_primary" data-bind="click: $parent.handleSsoLogin.bind($parent)"> Sign In
So far tried different elements but it doesn't find it
Here is a complete example of how you can go to login page and login, on terex parts (why you edited out the url, I don't know).
Assuming you have a working Selenium setup, you will also need the following imports:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time as t
[...]
wait = WebDriverWait(driver, 5)
url = 'https://parts.terex.com/'
driver.get(url)
t.sleep(3)
try:
wait.until(EC.element_to_be_clickable((By.ID, "CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll"))).click()
print('accepted cookies')
except Exception as e:
print('no cookie button!')
t.sleep(4)
login_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//button[#data-bind="click: $parent.handleSsoLogin.bind($parent)"]')))
login_button.click()
print('clicked login button')
t.sleep(5)
wait.until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, '//iframe[#class="truste_popframe"]')))
try:
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a[class='call']"))).click()
print('accepted cookies again')
except Exception as e:
print('no cookie iframe and button!')
driver.switch_to.default_content()
user_email_field = wait.until(EC.element_to_be_clickable((By.XPATH, '//input[#id="idcs-signin-basic-signin-form-username"]')))
user_email_field.send_keys('parts_dealer_112')
password_field = wait.until(EC.element_to_be_clickable((By.XPATH, '//input[#placeholder="Password"]')))
password_field.send_keys('password112')
login_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//oj-button[#id="idcs-signin-basic-signin-form-submit"]')))
login_button.click()
print('logged in unsuccessfully')
Selenium documentation can be found here: https://www.selenium.dev/documentation/
I have managed to locate the element using Chrome Plugin Selectors Hub
Selectors Hub Google Chrome. It allows quickly select Xpath for elements which then can be used with Xpath locator- makes life so much easier- highly recommend giving it a try if you are struggling.
login=driver.find_element(By.XPATH,"//button[#data-bind='click: $parent.handleSsoLogin.bind($parent)']").click()

How do I force Selenium Python to click on the correct button?

I'm very new to Selenium and am trying to build a scraper on this site that clicks on the "16. token URI" button, enters a number into the input field, and clicks the the Query button. But no matter how I define the element to be clicked, Selenium clicks on a different button, even thought I've copied the XPATH exactly. Obviously I can't move onto the next two steps until I solve this one. How do I force Selenium to scroll down to the 16th button and click it?
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import TimeoutException
import time
service = Service(executable_path=ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.maximize_window()
driver.get("https://etherscan.io/address/0xd0318da435dbce0b347cc6faa330b5a9889e3585#readContract")
assert "ASMBrain" in driver.title
try:
delay = 5
WebDriverWait(driver, delay).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "readcontractiframe")))
element = driver.find_element(By.XPATH, "//*[#id='readHeading16']/a")
# ActionChains(driver).move_to_element(element).click().perform()
driver.execute_script("arguments[0].scrollIntoView(true);", element)
WebDriverWait(driver, delay).until(EC.visibility_of((element))).click()
# driver.find_element(By.XPATH, "//input[#id='input_16_1']").send_keys('10')
# driver.find_element(By.XPATH, "//button[#id='btn_16']").click()
time.sleep(30)
driver.quit()
print("Page is ready!")
except TimeoutException:
print("Loading took too much time!")
I suggest using a different xpath. Try using the href of the a tag.
time.sleep(5)
element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, "//a[contains(text(), '16. tokenURI')]")))
element.click()
Message: element click intercepted: Element <iframe width="100%" id="readcontractiframe" src="/readContract?m=normal&a=0xd0318da435dbce0b347cc6faa330b5a9889e3585&v=0xd0318da435dbce0b347cc6faa330b5a9889e3585" frameborder="0" scrolling="no" style="height: 1019px; padding: 0px 0.5px;" cd_frame_id_="5f818ce91d8292c77481277348168d1d"></iframe> is not clickable at point (674, 633). Other element would receive the click: <div class="alert alert-light border shadow p-3" role="alert">...</div>
(Session info: chrome=96.0.4664.110)
You had an element click interception deal with the popup first. Then proceed to click it as well.
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,"#btnCookie"))).click()
try:
wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, "readcontractiframe")))
elem=wait.until(EC.element_to_be_clickable((By.XPATH,"//a[contains(.,'tokenURI')]")))
elem.click()
print("Page is ready!")
except Exception as e:
print(str(e))
print("Loading took too much time!")

I'm trying to use the <button class= instead of using the whole XPATH as the id: changes on each product

from selenium import webdriver
import time
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
from selenium.webdriver import ActionChains
PATH = "C:\Program Files (x86)\chromedriver.exe"
driver = webdriver.Chrome(PATH)
driver.maximize_window()
driver.get("https://accounts.ebuyer.com/customer/account/index.html?action=bG9naW4=")
title = driver.find_element_by_name("email")
title.clear()
title.send_keys("johnsmith#gmail.com")
password = driver.find_element_by_id("password")
password.send_keys("pass123")
driver.find_element_by_xpath('//*[#id="login"]/div[4]/input').click()
driver.find_element_by_xpath('/html/body/div[3]/div/button[2]').click()
#accepts cookies
driver.get("https://www.ebuyer.com/search?q=graphics+cards")
WebDriverWait(driver, 10)
try:
element = WebDriverWait(driver, 5).until(
EC.presence_of_element_located((By.XPATH,'//*[#id="grid-view"]/div[1]/div[4]/button'))
) #finds add to basket button
element.click()
driver.find_element_by_xpath('/html/body/header/div/div[3]/div/a[1]').click()
print("IN BASKET")
#adds to basket if found
except:
element = WebDriverWait(driver, 5).until(
EC.presence_of_element_located((By.XPATH,'//*[#id="main-
content"]/div/div[1]/div[2]/div[2]/div/div[2]/ul/li[2]/a'))
)
element.click()
#moves to next page
this is what I'm trying to click but the id changes on each product grid.
<button class="button button--mini-basket button--small js-add-to-mini-basket" data-product-
id="798879" data-ajax-basket-url="https://orders.ebuyer.com/customer/products/index.html?
action=YWpheF9jYXJ0X2FkZF9pdGVt" data-analytics-event="click" data-event-category="Search Listings - Grid" data-event-action="Product Click" data-event-label="Add to Basket Button">Add to
Basket</button>
I want to take <button class="button button--mini-basket button--small js-add-to-mini-basket" and
use this instead of By.XPATH,'//*[#id="grid-view"]/div[1]/div[4]/button'
I'm trying to scan the full page to find the Add to Basket Button and if it can't find that then it
will move on to the next page and repeat until it is found.
I have just built my first pc and I cannot get a graphics card anywhere so I want to use this grab
one.
I've recently found a love for coding so I'm quite new to this, I hope I've explained myself properly
and any help would be appreciated.
Use following xpath to identify. Use element_to_be_clickable() instead presence_of_element_located()
element =WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.XPATH,"//button[text()='Add to Basket']"))
Try following xpath
//button[#class='button button--mini-basket button--small js-add-to-mini-basket' and contains(text(),'Add to Basket')]

Selenium crashes when I'm trying to parse the next page (and seven after it) on a website. Any way to tackle this?

I want to parse an IMDb film rating located here on around 8 pages. In order to do that I'm using Selenium, and I'm having trouble with clicks, proceeding algorithm to next page. In the end I need 1000 titles when I'll continue using BeautifulSoup. Code below isn't working, I need to use button 'NEXT' with this HTML:
<a class="flat-button lister-page-next next-page" href="/list/ls000004717/?page=2">
Next
</a>
This is the code:
from selenium import webdriver as wb
browser = wb.Chrome()
browser.get('https://www.imdb.com/list/ls000004717/')
field = browser.find_element_by_name("flat-button lister-page-next next-page").click()
Error is the following:
NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":".flat-button lister-page-next next-page"}
(Session info: chrome=78.0.3904.108)
I suppose I lack knowledge of syntax needed, or maybe I mixed it up a little. I tried searching on SO, though every example is pretty unique and I don't possess the knowledge to extrapolate these cases fully. Any way Selenium can handle that?
You could try using an XPath to query on the Next text inside the button. You should also probably invoke WebDriverWait since you are navigating across multiple pages, then scroll into view since this is at the bottom of the page:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from time import sleep
browser = wb.Chrome()
browser.get('https://www.imdb.com/list/ls000004717/')
# keep clicking next until we reach the end
for i in range(0,9):
# wait up to 10s before locating next button
try:
next_button = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, "//a[contains(#class, 'page') and contains(text(), 'Next')]")))
# scroll down to button using Javascript
browser.execute_script("arguments[0].scrollIntoView(true);", next_button)
# click the button
# next_button.click() this throws exception -- replace with JS click
browser.execute_script("arguments[0].click();", next_button)
# I never recommend using sleep like this, but WebDriverWait is not waiting on next button to fully load, so it goes stale.
sleep(5)
# case: next button no longer exists, we have reached the end
except TimeoutException:
break
I also wrapped everything in a try / except TimeoutException block to handle the case where we have reached the end of pages, and Next button no longer exists, thus breaking out of the loop. This worked on multiple pages for me.
I also had to add an explicit sleep(5) because even after invoking WebDriverWait on element_to_be_clickable, next_button was still throwing StaleElementReferenceException. It seems like WebDriverWait was finishing before page was fully loaded, causing the status of next_button to change after it had been located. Normally adding sleep(5) is bad practice, but there did not seem to be another workaround here. If anyone else has a suggestion on this, feel free to comment / edit the answer.
There are a couple of ways that could work:
1. Use a selector for the next button and loop until the end:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
browser = webdriver.Chrome()
browser.get('https://www.imdb.com/list/ls000004717/')
selector = 'a[class*="next-page"]'
num_pages = 10
for page in range(pages):
# Wait for the element to load
WebDriverWait(browser, 10).until(ec.presence_of_element_located((By.CSS_SELECTOR, selector)))
# ... Do rating parsing here
browser.find_element_by_css_selector(selector).click()
Instead of clicking on the element, the other option could be to navigate to the next page using broswer.get('...'):
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
# Set up browser as before and navigate to the page
browser = webdriver.Chrome()
browser.get('https://www.imdb.com/list/ls000004717/')
selector = 'a[class*="next-page"]'
base_url = 'https://www.imdb.com/list/ls000004717/'
page_extension = '?page='
# Already at page = 1, so only needs to loop 9 times
for page in range(2, pages + 1):
# Wait for the page to load
WebDriverWait(browser, 10).until(ec.presence_of_element_located((By.CSS_SELECTOR, selector)))
# ... Do rating parsing here
next_page = base_url + page_extension + str(page)
browser.get(next_page)
As a note: field = browser.find_element_by_name("...").click() will not assign field to a webelement, as the click() method has no return value.
You could try a partial css selector.
browser.find_element_by_css_selector("a[class*='next-page']").click()
To click on the element with text as NEXT till the 901 - 1,000 of 1,000 page you have to:
scrollIntoView() the element once the visibility_of_element_located() is achieved.
Induce WebDriverWait for the element_to_be_clickable()
You can use the following solution:
Code Block:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options, executable_path=r'C:\WebDrivers\chromedriver.exe')
driver.get('https://www.imdb.com/list/ls000004717/')
driver.execute_script("return arguments[0].scrollIntoView(true);", WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "span.pagination-range"))))
while True:
try:
WebDriverWait(driver, 20).until(EC.invisibility_of_element((By.CSS_SELECTOR, "div.row.text-center.lister-working.hidden")))
driver.execute_script("return arguments[0].scrollIntoView(true);", WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "span.pagination-range"))))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a.flat-button.lister-page-next.next-page"))).click()
print("Clicked on NEXT button")
except TimeoutException as e:
print("No more NEXT button")
break
driver.quit()
Console Output:
Clicked on NEXT button
Clicked on NEXT button
Clicked on NEXT button
Clicked on NEXT button
Clicked on NEXT button
Clicked on NEXT button
Clicked on NEXT button
Clicked on NEXT button
Clicked on NEXT button
No more NEXT button

How do I find an element by its id in Selenium?

This is my code:
I have used the find element by id RESULT_RadioButton-7_0, but I am getting the following error:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome(executable_path="/home/real/Desktop/Selenium_with_python/SeleniumProjects/chromedriver_linux64/chromedriver")
driver.get("https://fs2.formsite.com/meherpavan/form2/index.html?153770259640")
radiostatus = driver.find_element(By.ID, "RESULT_RadioButton-7_0").click()
My error is this:
elementClickInterceptedException: element click intercepted: Element is not clickable at point (40, 567). Other element would receive the click: <label for="RESULT_RadioButton-7_0">...</label> (Session info: chrome=78.0.3904.70)
Based on the page link you provided, it looks like your locator strategy is correct here. If you are getting an error—most likely NoSuchElementException, I am assuming it might have something to do with waiting for the page to load before attempting to find the element. Let's use the ExpectedConditions class to wait on the element to exist before locating it:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Add the above references to your .py file
# Wait on the element to exist, and store its reference in radiostatus
radiostatus = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "RESULT_RadioButton-7_0")))
# Click the element
#radiostatus.click()
# Click intercepted workaround: JavaScript click
driver.execute_script("arguments[0].click();", radiostatus)
This will tick the radio button next to "Male" on the form.
Please find the below answer which will help you to click on the "Male" radio button from your link.
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome(executable_path=r"C:\New folder\chromedriver.exe")
driver.maximize_window()
driver.get('https://fs2.formsite.com/meherpavan/form2/index.html?153770259640')
# Clicking on the "Male" checkbox button
maleRadioButton = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "RESULT_RadioButton-7_0")))
ActionChains(driver).move_to_element(maleRadioButton).click().perform()
Unless you need to wait on the element (which doesn't seem necessary), you should be able to do the following:
element_to_click_or_whatever = driver.find_element_by_id('RESULT_RadioButton-7_0')
If you look at the source for find_element_by_id, it calls find_element with By.ID as an argument:
def find_element_by_id(self, id_):
return self.find_element(by=By.ID, value=id_)
IMO: find_element_by_id reads better, and it's one less package to import.
I don't think your issue is finding the element; there's an ElementClickInterceptedException when trying to click on the element. For example, the radio button is located, but (strangely) Selenium doesn't think it's displayed.
from selenium import webdriver
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://fs2.formsite.com/meherpavan/form2/index.html?153770259640")
radiostatus = driver.find_element_by_id('RESULT_RadioButton-7_0')
if radiostatus:
print('found')
# Found
print(radiostatus.is_displayed())
# False

Categories

Resources