How do I locate an input field via its label using webdriver?
I like to test a certain web form which unfortunately uses dynamically generated
ids, so they're unsuitable as identifiers.
Yet, the labels associated with each web element strike me as suitable.
Unfortunately I was not able to do it with the few suggestions
offered on the web. There is one thread here at SO, but which did not
yield an accepted answer:
Selenium WebDriver Java - Clicking on element by label not working on certain labels
To solve this problem in Java, it is commonly suggested to locate the label as an anchor via its text content and then specifying the xpath to the input element:
//label[contains(text(), 'TEXT_TO_FIND')]
I am not sure how to do this in python though.
My web element:
<div class="InputText">
<label for="INPUT">
<span>
LABEL TEXT
</span>
<span id="idd" class="Required" title="required">
*
</span>
</label>
<span class="Text">
<input id="INPUT" class="Text ColouredFocus" type="text" onchange="var wcall=wicketAjaxPost(';jsessionid= ... ;" maxlength="30" name="z1013400259" value=""></input>
</span>
<div class="RequiredLabel"> … </div>
<span> … </span>
</div>
Unfortunately I was not able to use CSS or XPATH expressions
on the site. IDs and names always changed.
The only solution to my problem I found was a dirty one - parsing
the source code of the page and extract the ids by string operations.
Certainly this is not the way webdriver was intended to be used, but
it works robustly.
Code:
lines = []
for line in driver.page_source.splitlines():
lines.append(line)
if 'LABEL TEXT 1' in line:
id_l1 = lines[-2].split('"', 2)[1]
You should start with a div and check that there is a label with an appropriate span inside, then get the input element from the span tag with class Text:
//div[#class='InputText' and contains(label/span, 'TEXT_TO_FIND')]/span[#class='Text']/input
Related
When using selenium to find an element tag using Xpath, it works using the xpath copied from chrome for that element, this was to test if it was working. Since the id element changes every time I open the webpage I am aware that this will cause an error in my web automation program, now from that same tag I am using the class element as it does not change every time I open the webpage but Selenium fails to locate that element at all. When I change the element in xpath to class with its relative name from the xpath I initially copied and tested from the webbroswer. What may be the problem?
Here is a example of the html source code I am wanting to go to and the Xpath:
<div class="popover fade right in" role="tooltip" id="popover784483" style="top: -9px; left: 328.5px; display: block;">
<div class="arrow" style="top: 88.9423%;"></div>
<h3 class="popover-title">
<font style="vertical-align: inherit;">
<font style="vertical-align: inherit;">Member details</font>
</font>
</h3>
<div class="popover-content">
<img class="center-block" src="http://api.vdarts.net:8080/picture/portrait/default.png" style="max-width:200px;height:auto;">
<hr>
<font style="vertical-align: inherit;">
<font style="vertical-align: inherit;">Account: CapitainJack </font>
Xpath intitially used but id changes:
//*[#id="popover784483"]/div[2]/font[1]/font
Xpath to be used:
//*[#class="popover fade right in"]/div[2]/font[1]/font
There are many ways to approach this issue.
You can match partial Text content Xpath like
//*[contains(text(), 'Account')]
You can use Img tag and following font like
(//img//following::font)[2]
I would recommend you use CSS selectors instead.
Compound class names are when an element has multiple classes separated by spaces. E.g. <div class="class1 class2 class3"></div>
if you want to select element with all 3 classes (in any order), you can use:
element = driver.find_element_by_css_selector(".class1.class2.class3")
If you want to use XPath, I have found that the following method works (using the same example as above):
browser.find_elements_by_xpath("//*[contains(concat(' ',#class,' '),' class1 ') and contains(concat(' ',#class,' '),' class2 ') and contains(concat(' ',#class,' '),' class3 ')]")
Note: you can use different boolean operators to filter out certain class names (e.g. 'and' 'and not' etc)
I've defined css selectors within the script to get the text within span elements and I'm getting them accordingly. However, the way I tried is definitely messy. I just seperated different css selectors using comma to let the script understand I'm after this or that.
If I opt for xpath I could have used 'div//span[.="Featured" or .="Sponsored"]' but in case of css selector I could not find anything similar to serve the same purpose. I know using 'span:contains("Featured"),span:contains("Sponsored")' I can get the text but there is the comma in between as usual.
What is the ideal way to locate the elements (within different ids) using css selectors except for comma?
My try so far with:
from lxml.html import fromstring
html = """
<div class="rest-list-information">
<a class="restaurant-header" href="/madison-wi/restaurants/pizza-hut">
Pizza Hut
</a>
<div id="featured other-dynamic-ids">
<span>Sponsored</span>
</div>
</div>
<div class="rest-list-information">
<a class="restaurant-header" href="/madison-wi/restaurants/salads-up">
Salads UP
</a>
<div id="other-dynamic-ids border">
<span>Featured</span>
</div>
</div>
"""
root = fromstring(html)
for item in root.cssselect("[id~='featured'] span,[id~='border'] span"):
print(item.text)
You can do:
.rest-list-information div span
But I think it's a bad idea to consider the comma messy. You won't find many stylesheets that don't have commas.
If you are just looking to get all 'span' text from the HTML then the following should suffice:
root_spans = root.xpath('//span')
for i, root_spans in enumerate(root_spans):
span_text = root_spans.xpath('.//text()')[0]
print(span_text)
Fairly new to coding and Python, I'm trying to use find_element_by_xpath to click the text highlighted text "Snoring Chin Strap by TheFamilyMarket".
time.sleep(2)
#btn = br.find_element_by_name("#Anti Snoring Chin Strap Kit")
# btn = br.find_element_by_link_text('Snoring Chin Strap')
The HTML code:
<div class="tableD">
<div class="productDiv" id="productDiv69507">
<h2 class="productTitle" id="productTitle69507" onclick="goToProduct(7)">Snoring Chin Strap by TheFamilyMarket</h2>
<img class="productImage" src="https://images-na.ssl-images-amazon.com/images/I/516fC3JruqL.jpg" onclick="goToProduct(7)">
<hr>
<h4 class="normalPrice" id="normalPrice7" onclick="goToProduct(7)">Normally: <span class="currency">$ </span>19.99</h4>
<h4 class="promoPrice" style="margin:2.5px auto;" id="promoPrice69507" onclick="goToProduct(7)">Your Amazon Price: <span class="currency">$ </span>1.99</h4>
<h3>Your Total: <span class="currency">$ </span>1.99</h3>
<p class="clickToViewP" id="cToVP69507" onclick="goToProduct(7)">Click to view and purchase!</p>
</div>
</div>
br.find_element_by_xpath("//h2[text()='Snoring Chin Strap by TheFamilyMarket']");
XPath is sometimes fast to get because you can get it from the browser, and that's why so many people use it, but in my opinion for long term, learning JavaScript and CSS selectors can help you in many instances in the future.
The above can be done also by selecting all the h2 elements and looking for text using plain JavaScript and passing the result to python:
link_you_search = br.execute_script('''
links= document.querySelectorAll("h2");
for (link of links) if (link.textContent.includes("Chin Strap")) return link;
''')
link_you_search.click()
or alternatively you can select by class:
link_you_search = br.execute_script('''
links= document.querySelectorAll(".productDiv");
for (link of links) if (link.textContent.includes("Chin Strap")) return link;
''')
link_you_search.click()
given that your element has an id attribute usually selecting by id it is best practice since it is the fastest search and you should only have only one element with that id and usually ids don't change so often in case of translation etc, so in your case it would be:
link_you_search = br.find_element_by_id('productTitle69507')
link_you_search.click()
How to identify the link, I have inspected the elements which are as below :
<div class="vmKOT" role="navigation">
<a class="Ml68il" href="https://www.google.com" aria-label="Search" data-track-as="Welcome Header Search"></a>
<a class="WaidDw" href="https://mail.google.com" aria-label="Mail" data-track-as="Welcome Header Mail"></a>
<a class="a4KP9d" href="https://maps.google.com" aria-label="Maps" data-track-as="Welcome Header Maps"></a>
<a class="QJOPee" href="https://www.youtube.com" aria-label="YouTube" data-track-as="Welcome Header YouTube"></a>
</div>
I want to identify the class WaidDw or href and click it using python.
You can try
driver.find_element_by_class_name('WaidDw').click()
or
driver.find_element_by_xpath('//a[#href="https://mail.google.com" and #aria-label="Mail"]').click()
In your provided HTML all attribute's values are unique, you can locate easily that element by using their attribute value.
As your question points to locate this <a class="WaidDw" href="https://mail.google.com" aria-label="Mail" data-track-as="Welcome Header Mail"></a> element. I'm providing you multiple cssSelectors which can work easily to identify the same element as below :-
a.WaidDw
a.WaidDw[href='https://mail.google.com']
a.WaidDw[aria-label='Mail']
a.WaidDw[data-track-as='Welcome Header Mail']
a.WaidDw[href='https://mail.google.com'][aria-label='Mail']
a.WaidDw[href='https://mail.google.com'][aria-label='Mail'][data-track-as='Welcome Header Mail']
Note :- Keep in practice (priority) to use cssSelector instead xpath if possible, because cssSelectors perform far better than xpath
Locating Element by CSS Selectors using python :-
element = driver.find_element_by_css_selector('use any one of the given above css selector')
Clicks the element :-
element.click()
Reference link :-
https://www.w3schools.com/cssref/css_selectors.asp
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors
I am trying to target a user in a list of other users. For example I created an automated test case to create a user named "tester1". I would now like to create a test case that finds and deletes "tester1" within a list of other users. Right now my work around is to find element by xpath which only targets a certain row within the user list.
Here is the webpage code that I am working with:
<span class="delete" data-reactid=".0.1.1.0.2.1.0.$usertree.1.0.0.$tester1.0.0.1">
<span class="icon-dash" data-reactid=".0.1.1.0.2.1.0.$usertree.1.0.0.$tester1.0.0.1.0"
></span>
Here is what I have been using for my workaround.
# Finds and clicks minus button to prompt deletion
# Deletes the 4th in the list / to change this, modify the number in the quotes below
element = driver.find_element_by_xpath("//tr[4]/td/div/span/span")
element.click()
# Finds and clicks Delete button
element = driver.find_element_by_xpath("//button[2]")
element.click()
EDIT:
<div class="tree-view_children" data-reactid=".0.1.1.0.2.1.0.$usertree.1"> <table class="ss-table" data-reactide=".0.1.1.0.2.1.0.$usertree.1.0">
<tbody data-reactid=".0.1.1.0.2.1.0.$usertree.1.0.0">
<tr class="user-list-item" data-reactid=".0.1.1.0.2.1.0.$usertree.1.0.0.$tester1">
<td data-reactid=".0.1.1.0.2.1.0.$usertree.1.0.0.$tester1.0">
<div data-reactid=".0.1.1.0.2.1.0.$usertree.1.0.0.$tester1.0.0">
<span class="delete" data-reactid=".0.1.1.0.2.1.0.$usertree.1.0.0.$tester1.0.0.1">
<span class="icon-dash" data- reactid=".0.1.1.0.2.1.0.$usertree.1.0.0.$tester1.0.0.1.0">
</span>
It looks like you can rely on the tester's name being a part of data-reactid attribute:
tester = "tester1"
delete_button = driver.find_element_by_xpath("//span[#class = 'delete' and contains(#data-reactid, '$%s.')]" % tester)
delete_button.click()