How can make an Xpath into a loop in python? - python

I have the following code:
button = driver.find_element_by_xpath("/html/body/div[3]/div/div[1]/div[2]/div[2]/div[2]/div[3]/div[1]")
ActionChains(driver).move_to_element(button).click(button).perform()
the next time i wanna click on this button using selenium the x path changes to
button = driver.find_element_by_xpath("/html/body/div[3]/div/div[1]/div[2]/div[2]/div[2]/div[3]/div[2]")
ActionChains(driver).move_to_element(button).click(button).perform()
I wanna convert this into a for look in the range(1,5). I used the below code:
l=[1,2,3,4,5]
string=str(l)
for i in string:
button = driver.find_element_by_xpath("/html/body/div[3]/div/div[1]/div[2]/div[2]/div[2]/div[3]/div"+i)
ActionChains(driver).move_to_element(button).click(button).perform()
time.sleep(5)
but I am getting the following error:
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.InvalidSelectorException: Message: invalid selector: Unable to locate an element with the xpath expression /html/body/div[3]/div/div[1]/div[2]/div[2]/div[2]/div[3]/div[ because of the following error:
SyntaxError: Failed to execute 'evaluate' on 'Document': The string '/html/body/div[3]/div/div[1]/div[2]/div[2]/div[2]/div[3]/div[' is not a valid XPath expression.
(Session info: chrome=83.0.4103.61)

Having large xpaths like that are fragile and difficult to navigate. You would probably have more success with a smaller, more accurate xpath.
Addressing your issue:
If you look at your error SyntaxError: Failed to execute 'evaluate' on 'Document': The string '/html/body/div[3]/div/div[1]/div[2]/div[2]/div[2]/div[3]/div[' is not a valid XPath expression.
This is not truncated. This is the xpath you're looking for - You're ending it with an open square bracket so it's not valid.
Have a look at making this xpath string valid before you feed it into find_by.
[edit - URL provided in the comments]
Looking at the page provided, try:
button = driver.find_element_by_xpath("//input[#class='amscroll-load-button']")
ActionChains(driver).move_to_element(button).click(button).perform()
It's a smaller xpath that goes right to the object without navigating the entire DOM.
When I run that xpath it always identifies just 1 object. Even if you click it and the page moves, wherever it moves still it still only identifies one.
If you want to use this, be aware there's an asynchronous page load when you click it. You'll also need a dynamic wait to let the data/page to load before you press it another time.
If you want to just see if it works, the lazy approach is to enter a few seconds of sleep/wait between the click commands.
If you want to know more about finding xpaths using devtools - have a look at this resource. Few videos at 10 minutes each can save a lot of headache on how to get the right objects.

Related

Unable to locate text input element using selenium and python on confluence

I am trying to click inside the text area on confluence and send some text to the page. I have tried a lot of combinations to find the text input element on the webpage but have been unsuccessful. The code I am using is as below -
button1 = driver.find_element_by_class_name('mce-content-body aui-theme-default mceContentBody wiki-content fullsize notranslate page-edit')
button1.click()
button1.send_keys(x)
driver.switch_to.frame("wysiwygTextarea_ifr")
It gives an error - no such element: Unable to locate element:
{"method":"css selector","selector":".mce-content-body
aui-theme-default mceContentBody wiki-content fullsize notranslate
page-edit"}
Please help me out have been trying various combinations but nothing worked.
added a snapshot for the sourcecode.
Going through your code and the DOM snapshot, I deduce that you are looking for this DOM component: DOM snapshot
In which case, the code you wrote is just opposite. You have first access the iframe and then you can access the elements inside of it (which you did the opposite way)
Refactored your code to align with the DOM:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it(driver.find_element_by_id("wysiwygTextarea_ifr")))
# changing the button 1 locator to xpath as the class name is too long and may not be accurate every time. data-id attribute instead would remain relatively static.
button1 = driver.find_element_by_xpath("//*[#data-id = 'wysiwygTextarea']")
button1.click()
button1.send_keys(x)

Python Selenium: Selecting from a list by text

I have spent the past few days trying to solve this problem. I store a string in a variable and i am trying to automate using selenium to select the item whose text()='string stored in the variable'.
I noticed i could not select some of the items in the list even though the text was exactly the same as the string i stored in the variable. The i realized today that some of the texts have a space before the next item. For example;
instead of (Architecture)
it says (Architecture )
This is the code i was running;
fc = 'COMMUNICATION'
faculty = WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.XPATH, '//*[#id="agentApplicationForm'
'"]/div/div[9]/div['
'1]/div/span/span/span[1]')))
print(faculty.is_displayed())
faculty.click()
sleep(5)
faculty_select = driver.find_element_by_xpath(f'//*[#id="Program1FacultyInstitute_listbox"]/li[text().StartsWith("{fc}")]')
faculty_select.click()
sleep(2)
I am now trying to use text().startsWith({fc}) but i don't think i am using a correct syntax.
This is the error i get;
selenium.common.exceptions.InvalidSelectorException: Message: invalid selector: Unable to locate an element with the xpath expression //*[#id="Program1FacultyInstitute_listbox"]/li[text().startsWith("COMMUNICATION")] because of the following error:
SyntaxError: Failed to execute 'evaluate' on 'Document': The string '//*[#id="Program1FacultyInstitute_listbox"]/li[text().startsWith("COMMUNICATION")]' is not a valid XPath expression.
(Session info: chrome=88.0.4324.96)
Can someone help me please.
Thank you very much.
Try this to search text starting with:-
//*[#id="Program1FacultyInstitute_listbox"]/li[starts-with(text(),'fc')]
Or maybe try using contains to do substring match like below. But you will need to pass more accurate text to search in order to avoid multiple matches.
//*[#id="Program1FacultyInstitute_listbox"]/li[contains(text(),'fc')]
if you want to select only (one) element based on (text)
you can use
faculty.click()
faculty.send_keys("value you want to select")
notice that this method works only if you want to select only one value based on string , also it works in droplist.

How to do xpath "and" / condition query correctly?

I am trying to set a checkmark on the prime option on amazon.fr.
Here is the link (the prime option is on the left): https://www.amazon.fr/gp/browse.html?node=2036893031.
Here is an image that shows the field I want to checkmark: https://ibb.co/ZY3mK3Z
I have it almost working. But it does not work for all amazon-categories, that's why I added the "and"-operator. Here is my xpath-query:
driver = webdriver.Chrome()
driver.get(category_url)
driver.find_element_by_xpath('//*[#id="leftNav"]/h4[text()="%s"]/following-sibling::ul//input[contains(#name, "s-ref-checkbox-")] and //*[#id="leftNav"]/h4[text()="%s"]/following-sibling::ul//input[contains(#name, "s-ref-checkbox-")]//i[contains(#class, "icon-prime")]' % ("Option d'expédition", "Option d'expédition"))
driver.click()
How can I format my query correctly? Is the and operator even necessary? I get the following error message:
TypeError: Failed to execute 'evaluate' on 'Document': The result is
not a node set, and therefore cannot be converted to the desired type.
I think you are trying to click without passing the WebElement.
You can find the checkbox based on the position of Prime label next to it.
Try the following xpath,
myprime = driver.find_element_by_xpath("//*[contains(#class,'icon-prime a-icon-small s-ref-text-link')]/parent::span/parent::label/input")
myprime.click();
I just tried the XPath below and it uniquely located the element
//label[.//i[contains(#class, 'a-icon-prime')]]/input
^ find a LABEL tag
^ that has a child I tag
^ that contains the class 'a-icon-prime' (indicating the prime logo)
^ then find an INPUT under the LABEL
The minimal working XPath locator would be:
//i[contains(#class,'small') and contains(#class,'prime')]
For better robustness and reliability I would recommend wrapping it into an Explicit Wait like:
prime = WebDriverWait(driver, 10).until(
expected_conditions.presence_of_element_located((By.XPATH, "//i[contains(#class,'small') and contains(#class,'prime')]")))
prime.click()
More information: How to use Selenium to test web applications using AJAX technology

How do I click a button using Selenium in Python?

I'm trying to crawl review data on an app from a Google Play website page using Python and Selenium. What I'm trying to do here is to click the "Full Review" button to see the entire text of each review.
But I keep running into these errors each time:
ElementNotInteractableException: Message: element not interactable
or
AttributeError: 'list' object has no attribute 'click'
or
NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":".LkLjZd ScJHi OzU4dc "}
The element for the button is this:
<button class="LkLjZd ScJHi OzU4dc " jsaction="click:TiglPc" jsname="gxjVle">Full Review</button>
The xpath for the button is this:
//*[#id="fcxH9b"]/div[4]/c-wiz/div/div[2]/div/div[1]/div/div/div[1]/div[2]/div/div[26]/div/div[2]/div[2]/span[1]/div/button
And this is the code I'm using for xpath:
full_review = driver.find_elements_by_xpath('//*[#id="fcxH9b"]/div[4]/c-wiz/div/div[2]/div/div[1]/div/div/div[1]/div[2]/div/div[26]/div/div[2]/div[2]/span[1]/div/button')
full_review.click()
I can't find the button by class name, xpath or anything.
Could anyone help me figure out this problem? In addition, is it possible to find the element by jsname?
I would really appreciate if you could help.
Avoid using xpath whenever possible, it's the most brittle selector.
id > CSS > Xpath
For your button, this css selector should work:
button[jsname='gxjVle']
You'll probably need to specify the child as that probably won't be unique
Your XPath selector is a little bit flaky, you can simplify it to be something like:
//button[text()='Full Review']
You're using the wrong function, if you're looking for a single unique element you should be using WebDriver.find_element_by_xpath one, mind that element, not elements
It's better to use Explicit Wait just in case element is not immediately available in DOM (for example if you're testing application built using AJAX technology)
Assuming all above:
full_review = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//button[text()='Full Review']")))

Unable to click on the Link Text, have tried Find_ELEMENT_BY_LINK_TEXT and quite a few other things , but its not working

SCREENSHOT OF THE HTML
Here is the screenshot of html code with which I am struggling , I want to click on the Smart Watches in the left-Nav and I am using the following code to click on it
driver.implicitly_wait(30)
driver.find_element_by_link_text('Smart Watches').click()
But I am getting the following error and I am clueless why i just cant find it on page
selenium.common.exceptions.NoSuchElementException: Message: no such
element: Unable to locate element: {"method":"link
text","selector":"Smart Watches"} (Session info:
chrome=60.0.3112.113) (Driver info: chromedriver=2.29.461591
(62ebf098771772160f391d75e589dc567915b233),platform=Windows NT
6.2.9200 x86_64)
I have also tried the explicit code and Expected conditions as follows -:
wait = WebDriverWait(driver, 20)
link = wait.until(expected_conditions.presence_of_element_located((By.LINK_TEXT,'"Smart Watches"')))
link.click()
But even its giving me Timeout exception
Here is the link of the page where I am stuck since morning
https://www.kogan.com/au/shop/phones/
I am very new to coding , any help would be helpful !! I just want to know why find_element_by_link_text is not working here , it looks weird to me!!
Thanks in advance
The problem is that when you use find_element_by_link_text(), it must be an exact match to the text contained in the link. In your HTML picture, you can see "Smart Watches" but what you aren't seeing is the SPAN just below but still inside the A is closed. Most likely if you expand it, you will see additional text that you must include if you are going to use find_element_by_link_text().
Another option is find_element_by_partial_link_text() which is more like a contains() instead of equals(). Depending on the page, it may find too many matches. You would have to try and see if it works.
Yet another option is using an XPath. There are a lot of different ways to create an XPath for this depending on exactly what you want.
This is the most general and thus most likely to find unwanted links but it may work. It's pretty much the same as find_element_by_partial_link_text()
//a[contains(.,'Smart Watches')
Other options include
//a[starts-with(.,'Smart Watches')
//li[#data-filter-facet='smart-watches']/a[contains(.,'Smart Watches')
//li[#data-filter-facet='smart-watches']/a[starts-with(.,'Smart Watches')
... and so on...
You can try this way...
Accessing text: find_element_by_xpath["//a[contains(text(), 'Smart Watches')]"].click()
Don't know why it is not wotks but partial link text works. Please see my java code for the same:
WebDriver driver=new FirefoxDriver();
driver.get("https://www.kogan.com/au/shop/phones/");
WebElement watch=driver.findElement(By.partialLinkText("Smart Watch"));
WebDriverWait waitElement=new WebDriverWait(driver, 30);
waitElement.until(ExpectedConditions.elementToBeClickable(watch));
watch.click();
You need to add double quotation marks, as it is in the html code:
driver.find_element_by_link_text('"Smart Watches"').click()
most of the time it might happen that link is taking some more time to load after your page has loaded. rather than using implicit wait use explicit wait.
wait = WebDriverWait(driver, 30)
link = wait.until(expected_conditions.presence_of_element_located((By.LINK_TEXT,"Smart Watches")))
link.click()
it could also be the case that link is inside another frame, in this case you will have to switch to this frame.

Categories

Resources