Xpath locator unable to detect the element - python

I am trying to select a button using selenium however i believe i am doing something wrong while writing my xpath can anyone please help me on this i need to select the currency Euro.
link :- https://www.booking.com/
Locator which i want to select
Locator which i have written
USD = self.find_element_by_xpath(f"//a[contains(text(),'selected_currency='Euro']")
USD.click()

The below xpath
//a[contains(#href,'EUR') and starts-with(#class,'bui-list')]
is present two times in HTML DOM.
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the xpath and see, if your desired element is getting highlighted with 1/1 matching node.
In case you would like to select the first one which is in Suggest for you, there is no need to do anything with respect to XPath.
#pmadhu answer is misleading, since why would anyone look for first index in XPath when using with Selenium ? If there are multiple matching node, Selenium is always going to pick up the first element, So it really does not make any sense to me that why would someone use [1]
Nevertheless,
to click on Suggest for you EURO :
try:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[contains(#href,'EUR') and starts-with(#class,'bui-list')]"))).click()
except:
pass
Imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
In case you are looking to click on second matching node for EUR,
in that case it make sense to use index 2.
XPath would look something like this :
(//a[contains(#href,'EUR') and starts-with(#class,'bui-list')])[2]

The text you are looking for: selected_currency='EUR' is in the data-modal-header-async-url-param parameter of the a tag. You should run the contains on that.
Edit:
Locator: //a[contains(#data-modal-header-async-url-param, 'selected_currency=EUR')]

As already explained, selected_currency=EUR is in the attribute - data-modal-header-async-url-param.
However you can select the required option, with below code.
The xpath for the EUR option can be - //div[contains(text(),'EUR')]. Since it highlights 2 elements in the DOM using this xpath- (//div[contains(text(),'EUR')])[1]. Its important to find unique locators. Link to refer
# Imports required for Explicit wait
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver.get("https://www.booking.com/")
wait = WebDriverWait(driver,30)
# Click on Choose currency option
wait.until(EC.element_to_be_clickable((By.XPATH,"//span[#class='bui-button__text']/span[contains(text(),'INR')]"))).click()
# Click on the EUR option.
euro_option = wait.until(EC.element_to_be_clickable((By.XPATH,"(//div[contains(text(),'EUR')])[1]")))
euro_option.click()

Related

Python Selenium How to Select from Dropdown?

I was testing my code over: https://semantic-ui.com/modules/dropdown.html
I wrote the following code in Python3 which finds all drop-downs in a given webpage and selects the last option for each drop-down:
dropdowns = driver.find_elements(By.XPATH, '//select[#class="ui dropdown"]')
print(str(len(form_dropdowns)))
for drop_down in form_dropdowns:
driver.execute_script("arguments[0].click();", drop_down)
options = drop_down.find_elements(by=By.TAG_NAME, value='option')
print(str(len(options)))
driver.execute_script("arguments[0].click();", options[len(options) - 1])
time.sleep(100)
I see the following printed on screen:
2
3
3
Which means 2 drop-downs were found, both with 3 options to select from.
BUT I don't see any value being changed in the UI, why is that?
Although it seems OP's approach to select the last option using the following line of code is working,
driver.execute_script("arguments[0].click();", options[len(options) - 1])
I'm totally against the idea of selecting the last option.
Ideally to interact with any html-select element we must be using the Select() class and use either among the option index, option value or option text to choose the desired <option>.
As an example,
Using select_by_value():
Select(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "xpath_select_element")))).select_by_value("value")
Using select_by_visible_text():
Select(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "xpath_select_element")))).select_by_visible_text("text")
Note : You have to add the following imports :
from selenium.webdriver.support.ui import Select
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:
Selecting options using Selenium and Python

How to select a value from drop down menu in python selenium

I am writing a python script which will call a webpage and will select an option from the drop down to download that file. To do this task, I am using chropath. It is a browser extension which can give you the relative xpath or id for any button or field on the webpage and using that we can call it from python selenium script.
Above image shows the drop down menu in which I have to select 2019 as year and the download the file. In the lower part of the image, you can see that I have used chropath to get the relative xpath of the drop down menu which is //select[#id='rain']
Below is the code I am using:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get("<URL>")
driver.maximize_window()
grbf = driver.find_element_by_xpath("//select[#id='rain']")
grbf.send_keys('2019')
grbf_btn = (By.XPATH, "//form[1]//input[1]")
WebDriverWait(driver, 20).until(EC.element_to_be_clickable(grbf_btn)).click()
from the above code, you can see that I am using xpath to select the drop down grbf = driver.find_element_by_xpath("//select[#id='rain']") and then sending keys as 2019 i.e. grbf.send_keys('2019') and after that I am calling download button to download it. But for some reason, its always selecting year 1999 from the drop down. I am not able to understand what is wrong in this. Is this correct approach to solve this. Please help. Thanks
I had the same problem time ago. Try this:
from selenium.webdriver.support.ui import Select
grbf = Select(driver.find_element_by_xpath("//select[#id='rain']"))
grbf.select_by_value('2019')
In the select_by_value() you have to use the value of the element in the dropdown.
By the way, if an element has id, use it.
grbf = Select(driver.find_element_by_id('rain'))
Try below code:
select = Select(driver.find_element_by_xpath("//select[#id='rain']"))
select.select_by_visible_text('2019')
Another approches to deal with dropdown:
Using Index of Dropdown :
select.select_by_index(Paass index)
Using valueof Dropdown :
select.select_by_value('value of element')
Using visible text of Dropdown :
select.select_by_visible_text('element_text')
In my opinion, I don't think this is the correct approach. You try to select the option which is dropdown (not a text box like ), so send key command does not work.
What you need to do is try to inspect HTML changing when clicking the dropdown and try to XPath for an option that you want to select.
If you still stuck at this problem, I recommend using katalon recorder which is a chrome extension to allow you to record and do UI testing

What would be the intractable XPATH / element to type in text into a Google Doc?

I am running a code in Python that is to open a Google Doc and type in a certain set of combinations for a set length. I have the code that allows me to go to my Google Docs and open up a new document, however when I try to find the XPATH or element to type in text into the doc itself, I keep getting an error that says:
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
Currently, I keep trying to see if the XPATH is //*[#id="kix-appview"]/div[7]/div/div[1]/div[1]/div/div/div/div[2]/div/div[2]/div[1]/div/div/div[1]/div/div/div/div/div/span[2]/span/span could be shorter but I don't care about how large the file size is. If anyone is able to help out or happens to know the XPATH off the top of your head, all help would be appreciated.
Try below xpath :
wait = WebDriverWait(driver, 30)
wait.until(EC.element_to_be_clickable((By.XPATH, "//*[#id='kix-appview']/div[7]/div/div[1]/div[1]/div/div/div/div[2]/div/div[2]/div[1]/div/div/div[1]/div/div/div/div/div/span[2]/span/span")))
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

Python Selenium - Attempting to write wait condition for when text changes in table element

I am attempting to write a selenium script to search for terms on a webpage, then select them from a table.
The table is dynamic and changes when elements are entered into the search field. Typically when I have written selenium code in the past, I have just used wait statements to wait for some element on the page to load before continuing. With this, I specifically need to wait until the element I am looking for to appear in the table, and then to select it.
Here is what I currently have written, where tableElement is the table I attempting to search through, and userID is the input I am hoping to find:
tableElement = self.driver.find_element_by_xpath(
'X-PATH_TO_ELEMENT')
ui.WebDriverWait(self.driver, 15).until(
EC.text_to_be_present_in_element(
tableElement, userID)
)
When running this code, I receive the following error message:
find_element() argument after * must be an iterable, not WebElement
As far as I am aware, this should be the correct syntax for the method I am attempting to call. Any help would be appreciated! Please let me know if I need to elaborate on any details.
Expcted condition are basically used with find_element and find_elements.
In your code you have provided web element to EC instead of locator.
you can use below code to use EC in your code :
WebDriverWait(driver, 30).until(
EC.visibility_of_all_elements_located((By.XPATH, "xpath of your element")))
Note: you have to add below importss to your solution:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

How to find element based on what its value ends with in Selenium?

I am dealing with a situation where every time I login a report is displayed in a table whose ID is dynamically generated with random text ending with "table".
I am automating this table with selenium python web driver. It has Syntax
driver.find_element_by_xpath('//*[#id="isc_43table"]/tbody/tr[1]/td[11]').click();
help me editing this syntax to match it with table ending id with "table".
(only one table is generated).
The ends-with XPath Constraint Function is part of XPath v2.0 but as per the current implementation Selenium supports XPath v1.0.
As per the HTML you have shared to identify the element you can use either of the Locator Strategies:
XPath using contains():
driver.find_element_by_xpath("//*[contains(#id,'table')]/tbody/tr[1]/td[11]").click();
Further, as you have mentioned that table whose ID is dynamically generated so to invoke click() on the desired element you need to induce WebDriverWait for the element to be clickable and you can use the following solution:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//*[contains(#id,'table')]/tbody/tr[1]/td[11]"))).click()
Alternatively, you can also use CssSelector as:
driver.find_element_by_css_selector("[id$='table']>tbody>tr>td:nth-of-type(11)").click();
Again, you can also use CssSelector inducing WebDriverWait as:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "[id$='table']>tbody>tr>td:nth-of-type(11)"))).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
I hope, either these 2 will work for you
driver.find_element_by_xpath("//table[ends-with(#id,'table')]/tbody/tr[1]/td[11]").click();
OR
driver.find_element_by_xpath("//table[substring(#id,'table')]/tbody/tr[1]/td[11]").click();
If not getting, remove the tags from tbody.
For such situations, when you face randomly generated ids, you can use the below functions with XPATH expression
1) Contains,
2) Starts-with &
3) Ends-with
4) substring
Syntax
//table[ends-with(#id,'table')]
//h4/a[contains(text(),'SAP M')]
//div[substring(#id,'table')]
You need to identify the element which is having that id, whether its div or input or table. I think its a table.
You can try below XPath to simulate ends-with() syntax:
'//table[substring(#id, string-length(#id) - string-length("table") +1) = "table"]//tr[1]/td[11]'
You can also use CSS selector:
'table[id$="table"] tr>td:nth-of-type(11)'

Categories