How to click on a button with Selenium - python

I try to catch the "next" button in a viewer with Selenium in Python, but nothing works and I get an error message.
The code I executed:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
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'chromedriver.exe')
driver.get('https://web.nli.org.il/sites/NLI/Hebrew/digitallibrary/pages/viewer.aspx?&presentorid=MANUSCRIPTS&docid=PNX_MANUSCRIPTS990000907570205171-1')
WebDriverWait(driver, 10)
Until now, everything has been fine. This is where the issue arises.
I want to click on the next arrow:
I get the following code while inspecting the source code of this arrow:
<div id="next" class="left"> </div>
So these are my attempts:
XPath
driver.find_elements_by_xpath('//*[#id="next"]')
returns an empty list.
id
driver.find_elements_by_id("next")
returns an empty list.
So, how can I catch this button and click on it?

That arrow is in iframe, so driver needs to change it's focus.
and then you can use explicit wait to click on it :
CSS_SELECTOR :
div#next
Sample code :
driver = webdriver.Chrome(options=options, executable_path=r'chromedriver.exe')
driver.get('URL here')
WebDriverWait(driver, 10)
wait = WebDriverWait(driver, 10)
wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, "MainIframe")))
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div#next"))).click()
Imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

you can use below css selectors:
.left [title='Next']
div.left
div .left [title='Next']

//div[#id='next']//child::a there could be different element with the id next so specifically define for the div and, I can see the a is the child of div
you can check it with the explicitWait
wait = WebDriverWait(driver,10)
wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#id='next']//child::a"))).click()
Also found an iframe with the id = MainIframe and name = zoomer
under which the desired element is available, so you could switch
to the frame and get the desired element

Related

selenium python element select from dropdown menu

Trying to select multiple elements from dropdown menu via selenium in python.
Website from URL. But Timeoutexception error is occurring.
I have tried Inspect menu from GoogleChrome. //label[#for="inputGenre"]/parent::div//select[#placeholder="Choose a Category"] gives exactly the select tag that I need. But unfortunately, with selenium I cannot locate any element within this tag. Any ideas why the error occur?
code is below;
slect_element = Select(WebDriverWait(driver, 10).until(EC.element_located_to_be_selected((By.XPATH, '//label[#for="inputGenre"]/parent::div//select[#placeholder="Choose a Category"]'))))
slect_element.select_by_index(1)
slect_element.select_by_value('23')
strangeness is it is possible to locate it and get its text values from code below;
drp_menu=driver.find_elements(By.XPATH,'//label[#for="inputGenre"]/parent::div//div[#class="dropdown-main"]/ul/li')
print(len(drp_menu))
ls_categories=[]
for i in drp_menu:
ls_categories.append(i.get_attribute('innerText'))
print is giving 15 elements, and get_attribute(innerText) gives text of each option element text.
Anyway, Thanks a lot #Prophet
That Select element is hidden and can't be used by Selenium as we use normal Select elements to select drop-down menu items.
Here we need to open the drop-down as we open any other elements by clicking them, select the desired options and click the Search button.
So, these lines are opening that drop down and selecting 2 options in the drop-down menu:
wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#class='form-group'][contains(.,'Category')]//div[#class='dropdown-display-label']"))).click()
wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#class='form-group'][contains(.,'Category')]//li[#data-value='23']"))).click()
wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#class='form-group'][contains(.,'Category')]//li[#data-value='1']"))).click()
The result so far is:
And by finally clicking the Search button the result is:
The entire code is:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
options = Options()
options.add_argument("start-maximized")
webdriver_service = Service('C:\webdrivers\chromedriver.exe')
driver = webdriver.Chrome(service=webdriver_service, options=options)
wait = WebDriverWait(driver, 20)
url = "https://channelcrawler.com/"
driver.get(url)
wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#class='form-group'][contains(.,'Category')]//div[#class='dropdown-display-label']"))).click()
wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#class='form-group'][contains(.,'Category')]//li[#data-value='23']"))).click()
wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#class='form-group'][contains(.,'Category')]//li[#data-value='1']"))).click()
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type='submit']"))).click()

selenium chromedriver different values of xpath between terminal and actual driver

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
url = 'https://www.msha.gov/mine-data-retrieval-system'
driver = webdriver.Chrome(executable_path='chromedriver')
driver.get(url)
#driver.find_element_by_xpath('//*[#id="mstr90"]/div[1]/div/div') error
#driver.find_elements_by_xpath('//input') gives 3 while in driver gives 10
I am unable to find element where the input "Search by Mine ID by typing here.." is, the document is fully loaded but it can't locate it. What I want to do is simply pass in an input "0100003" then submit
Iframe is present on your page. Before you interact with inputbox you need to switch on to iframee. Refer below code to resolve your issue.
wait = WebDriverWait(driver, 10)
driver.get("https://www.msha.gov/mine-data-retrieval-system")
driver.switch_to.frame("iframe1")
wait = WebDriverWait(driver, 10)
inputBox = wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#class='mstrmojo-SimpleObjectInputBox-empty']"))).click()
inputBox1 = wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#class='mstrmojo-SimpleObjectInputBox-container mstrmojo-scrollNode']//input")))
inputBox1.send_keys("0100003")
Updated Code to handle dropdown
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div#mstr100,mstrmojo-Popup.mstrmojo.SearchBoxSelector-suggest"))).click()
Note: please add below imports to your solution
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
Output:
The element you are trying to find is inside an iframe, so you will need to switch to that iframe first and then do your find element. Also, it's a best practice to use waits to give pages/elements time to load before a find element timeouts and throws an error.
iframe = WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#iframe1')))
driver.switch_to.frame(iframe)
mine_id = WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.XPATH, '//*[#id="mstr90"]/div[1]/div/div')))
Then you need to click this element to make it interactable.
mine_id.click()
Once you click then you need to re-find the input box before sending keys.
mine_id_input = WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mstr90 input')))
mine_id_input.send_keys('0100003')
To select the suggestion displayed:
suggestion = WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#mstr100')))
suggestion.click()
if you wanted to continue on interacting outside the iframe after this is done, you will want to switch back out of the iframe like this:
driver.switch_to.default_content()

Selenium Webdriver (Python) - Click on a div element (checkbox)

I am trying to click on a non-button element (checkbox) inside an iframe but am not able to click on it using the selenium webdriver. The URL is https://www.nissanoflithiasprings.com/schedule-service and the box that I want to click is shown in the screenshot below:
NOTE: Select the following options to reach the screen shown in the screenshot below: Click on New Customer "MAKE. MODEL. YEAR". Select Make as "NISSAN" -> Year as "2018" -> Model as "ALTIMA" -> Trim as "SL" -> Engine Type as "I4" -> Enter Mileage as "35000" -> Click on "CONTINUE" at the bottom. On the following page, the goal is to click on the checkbox Maintenance Package Standard / Schedule 1 (the checkbox needs to be clicked but I am not able to find the correct code line for Selenium to be able to click on it)
Below is the working Selenium Python script that I wrote to successfully navigate until the page that shows the checkbox that I wish to click:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
chrome_path = r"C:\Users\gh456\Downloads\chromedriver_win32\chromedriver.exe"
driver = webdriver.Chrome(chrome_path)
driver.maximize_window()
driver.get("https://www.nissanoflithiasprings.com/schedule-service")
wait = WebDriverWait(driver, 10)
# first frame - by css selector
wait.until(ec.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, '[src^="https://consumer.xtime.com"]')))
# second frame - by ID
wait.until(ec.frame_to_be_available_and_switch_to_it('xt01'))
driver.find_element_by_id("new_customer_button").click()
driver.find_element_by_id("NISSAN").click()
wait.until(ec.visibility_of_element_located((By.ID, "2018"))).click()
wait.until(ec.visibility_of_element_located((By.ID, "ALTIMA"))).click()
wait.until(ec.visibility_of_element_located((By.ID, "SL"))).click()
wait.until(ec.visibility_of_element_located((By.ID, "I4"))).click()
wait.until(ec.visibility_of_element_located((By.NAME, "mileage_input"))).send_keys("35000")
wait.until(ec.visibility_of_element_located((By.ID, "continue_button"))).click()
# Click on the checkbox
# ---??????????????????
Can someone help me with the correct code to make selenium webdriver to click that checkbox?
The element is covered by another element...
Also, I changed the expected_conditions as element_to_be_clickable().
So you can use ActionChains:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException, NoSuchElementException
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.common.action_chains import ActionChains
chrome_path = r"C:\Users\gh456\Downloads\chromedriver_win32\chromedriver.exe"
driver = webdriver.Chrome(chrome_path)
driver.maximize_window()
driver.get("https://www.nissanoflithiasprings.com/schedule-service")
wait = WebDriverWait(driver, 10)
# first frame - by css selector
wait.until(ec.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, '[src^="https://consumer.xtime.com"]')))
# second frame - by ID
wait.until(ec.frame_to_be_available_and_switch_to_it('xt01'))
driver.find_element_by_id("new_customer_button").click()
driver.find_element_by_id("NISSAN").click()
wait.until(ec.element_to_be_clickable((By.ID, "2018"))).click()
wait.until(ec.element_to_be_clickable((By.ID, "ALTIMA"))).click()
wait.until(ec.element_to_be_clickable((By.ID, "SL"))).click()
wait.until(ec.element_to_be_clickable((By.ID, "I4"))).click()
wait.until(ec.visibility_of_element_located((By.NAME, "mileage_input"))).send_keys("35000")
wait.until(ec.element_to_be_clickable((By.ID, "continue_button"))).click()
check_box_el = wait.until(ec.visibility_of_element_located((By.XPATH, '//div[#id="maintenance_package_section"]//label[#class="checkbox"]')))
ActionChains(driver).move_to_element(check_box_el).click().perform()
Screenshot:
You might want to use CSS_SELECTOR and not XPATH:
check_box_el = wait.until(ec.visibility_of_element_located((By.CSS_SELECTOR, '#maintenance_package_section > div label')))
ActionChains(driver).move_to_element(check_box_el).click().perform()
Try this locator (//*[#class="checkbox"])[1] and use ActionChains.
chk = wait.until(ec.element_to_be_clickable((By.XPATH, '(//*[#class="checkbox"])[1]')))
ActionChains(driver).move_to_element(chk).click().perform()
You can change [1] to [2] or [3] if you want
It seems to be your check box is not enabled. Please, have some conditions following is_selected()...And check whether it is enabled now.....
http://selenium-interview-questions.blogspot.com/2014/03/working-with-checkboxes-in-selenium.html

Selenium Webdriver (Python) - Unable to locate element inside nested iframes

I am trying to scrape some data from an iframe located within a webpage. The URL of the webpage is https://www.nissanoflithiasprings.com/schedule-service. I am trying to access the button shown in the image below:
When I right-click on the button (located inside the iframe) to view the source code, I am able to see the HTML id and name (see screenshot below):
The "id" for the button is "new_customer_button". However, when I use selenium webdriver's driver.find_element_by_id("new_customer_button") to access the button, the code is not able to locate the button inside the iframe and throws the following error:
NoSuchElementException: no such element: Unable to locate element: {"method":"id","selector":"new_customer_button"}
Below is the code that I have tried so far:
from selenium import webdriver
chrome_path = r"C:\Users\gh455\Downloads\chromedriver_win32\chromedriver.exe"
driver = webdriver.Chrome(chrome_path)
driver.get("https://www.nissanoflithiasprings.com/schedule-service")
dest_iframe = driver.find_elements_by_tag_name('iframe')[0]
driver.switch_to.frame(dest_iframe)
driver.find_element_by_id("new_customer_button")
Not sure why this is happening. Any help will be appreciated. Thanks!
The element is inside multiple <iframe> tags, you need to switch to them one by one. You should also maximize the window and use explicit wait as it take some time to load
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
chrome_path = r"C:\Users\gh455\Downloads\chromedriver_win32\chromedriver.exe"
driver = webdriver.Chrome(chrome_path)
driver.maximize_window()
driver.get("https://www.nissanoflithiasprings.com/schedule-service")
wait = WebDriverWait(driver, 10)
# first frame - by css selector
wait.until(ec.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, '[src^="https://consumer.xtime.com"]')))
# second frame - by ID
wait.until(ec.frame_to_be_available_and_switch_to_it('xt01'))
driver.find_element_by_id("new_customer_button")
To click() on the element with text as Make · Year · Model as the the desired element is within an nested <iframe>s so you have to:
Induce WebDriverWait for the desired parent frame to be available and switch to it.
Induce WebDriverWait for the desired child frame to be available and switch to it.
Induce WebDriverWait for the desired 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
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("start-maximized")
chrome_options.add_argument('disable-infobars')
driver = webdriver.Chrome(options=chrome_options, executable_path=r'C:\WebDrivers\chromedriver.exe')
driver.get("https://www.nissanoflithiasprings.com/schedule-service")
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[src*='com/scheduling']")))
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[src*='consumerportal']")))
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.button.button--action.btn.btn-secondary#new_customer_button"))).click()
Browser Snapshot:
Here you can find a relevant discussion on Ways to deal with #document under iframe

Selenium in Python expected conditions works with Firefox but not Chrome

I log into a private site and then wait for a link text to appear and then open the link with browser.get(). The code below throws a timeout exception almost every time while waiting for the link text "OTD" to appear. It is strange that it works once out of many tries. Even stranger is that if I use a sleep timer instead of the wait for expected condition, it works, but that is not what I want to use.
Here is the html:
<a target="_blank" href="/privateurl">OTD</a>
And here is the code that uses chromedriver:
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
import webbrowser
chrome_options = webdriver.ChromeOptions()
prefs = {'download.default_directory' : 'E:\\folder'}
chrome_options.add_experimental_option('prefs', prefs)
browser = webdriver.Chrome(chrome_options=chrome_options)
#browser.get('private url login page')
#enter login information and submit
wait = WebDriverWait(browser, 10)
wait.until(
EC.presence_of_element_located((By.LINK_TEXT, "OTD"))
)
browser.get('private url')
I have the same code, but for the Firefox driver and it works perfectly every time. I just need to use Chrome browser instead.
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
import webbrowser
profile = webdriver.FirefoxProfile()
profile.set_preference("browser.download.folderList", 2)
profile.set_preference("browser.download.dir", 'E:\\folder')
profile.set_preference("browser.download.useDownloadDir", True)
browser=webdriver.Firefox(profile)
#browser.get('private url login page')
#enter login information and submit
wait = WebDriverWait(browser, 10)
wait.until(
EC.presence_of_element_located((By.LINK_TEXT, "OTD"))
)
browser.get('private url')
What am I doing wrong in the code using the chromedriver that is making it throw a timeout exception?
There are a couple of things to address :
Finally as you are invoking click() on the WebElement so instead of the expected_conditions clause as presence_of_element_located() you should use the clause element_to_be_clickable(locator).
When you use expected_conditions clause as element_to_be_clickable(locator) the WebElement is returned back and you can directly invoke click() method on it.
Your optimized line of code will be :
WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.LINK_TEXT, "OTD"))).click()
Update A
As per your comment update you are seeing the error :
'element_to_be_clickable' object has no attribute 'click'
An alternative would be to extract the href attribute and invoke get() as follows :
element = WebDriverWait(browser, 10).until(EC.visibility_of_element_located((By.LINK_TEXT, "OTD")))
attr_href = element.get_attribute("href")
driver.get(attr_href)
Update B
As per your comment update the idea of Selenium does interact with the element ... even though it is unable to attain visibility_of_element is not a full proof solution as :
The expected_conditions clause presence_of_element_located(locator) mentions :
class selenium.webdriver.support.expected_conditions.presence_of_element_located(locator)
An expectation for checking that an element is present on the DOM of a page. This does not necessarily mean that the element is visible.
locator - used to find the element returns the WebElement once it is located.
Where as the expected_conditions clause visibility_of_element_located(locator) mentions :
class selenium.webdriver.support.expected_conditions.visibility_of_element_located(locator)
An expectation for checking that an element is present on the DOM of a page and visible. Visibility means that the element is not only displayed but also has a height and width that is greater than 0.
locator - used to find the element returns the WebElement once it is located and visible.
From Selenium perspective if an element is not displayed Selenium won't be interact with the element e.g. invoking click()

Categories