How to use array of XPath in robotframework - selenium

I have html table which has some one column and N rows. I want to traverse through the array. Since HTML table does not have unique locator. I am using #class attribute to get the rows This is my xpath which gives me matching rows.
//td[contains(#class,'td-entity-field-super-parent')].
When i add index to it like this:
(//td[contains(#class,'td-entity-field-super-parent')])[3],
it works fine in firebox/seleniumIDE.
However with RobotFramework, it works only for first row.
Works:
//td[contains(#class,'td-entity-field-super-parent')][1]
Does not work:
//td[contains(#class,'td-entity-field-super-parent')][2]
//td[contains(#class,'td-entity-field-super-parent')][3]
//td[contains(#class,'td-entity-field-super-parent')][4]
BTW, enclosing entire element in round bracket does not work.
(//td[contains(#class,'td-entity-field-super-parent')])[4]
Can someone please help me here.

Ok. Here is the answer. Simply use "xpath=" as prefix to your xpath. Here is the example
xpath=(//td[contains(#class,'td-entity-field-super-parent')])[4]

Related

Selenium finding elements returns incorrect elements

I'm using Selenium to try and get some elements on a web page but I'm having trouble getting the ones I want. I'm getting some, but they're not the ones I want.
So what I have on my page are five divs that look like this:
<div class="membershipDetails">
Inside each one is something like this:
<div class="membershipDetail">
<h3>
VIP Membership
</h3>
</div>
They DO all have this same link, but they don't have the same text ('VIP Membership' would be replaced by something else)
So the first thing was to get all the divs above in a list. This is the line I use:
listElementsMembership = driver.find_elements_by_css_selector(div[class^='membershipDetail'])
This gives me five elements, just as I would expect. I checked the 'class' attribute name and they are what I would expect. At this point I should say that they aren't all EXACTLY the same name 'membershipDetail'. Some have variations. But I can see that I have all five.
The next thing is to go through these elements and try and get that element which contains the href ('VIP Membership').
So I did that like this:
for elem in listElementsMembership:
elemDetailsLink = elem.find_element_by_xpath('//a[contains(#href,"EditMembership")]')
Now this does return something, but it always got me the element from the FIRST of the five elements. It's as if the 'elem.find_element_by_xpath' line is going up a level first before finding these hrefs. I kind of confirmed this by switching this to a 'find_elements_by_xpath' (plural) and getting, you guessed it, five elements.
So is this line:
elemDetailsLink = elem.find_element_by_xpath('//a[contains(#href,"EditMembership")]')
going up a level before getting its results? If it is, now can I make it not do that and just restrict itself to the children?
If you are trying to find element with in an element use a . in the xpath like below:
listElementsMembership = driver.find_elements_by_css_selector(div[class^='membershipDetail'])
for elem in listElementsMembership:
elemDetailsLink = elem.find_element_by_xpath('.//a') # Finds the "a" tag with respect to "elem"
Suppose if you are looking for VIP Membership:
listElementsMembership = driver.find_elements_by_css_selector(div[class^='membershipDetail'])
for elem in listElementsMembership:
value = elem.find_element_by_xpath('.//a').get_attribute("innerText")
if "VIP Membership" in value:
print(elem.find_element_by_xpath('.//a').get_attribute("innerText"))
And if you dont want iterate over all the five elements try to use xpath like below: (As per the HTML you have shared)
//div[#class='membershipDetail']//a[text()='VIP Membership']
Or
//div[#class='membershipDetail']//a[contains(text(),'VIP Membership')]
You've few mistake in that css selector.
Quotes are missing.
^ is for starts-with, not sure if you really need that. In case it's partial matching please use * instead of ^
Also, I do not see any logic for the below statement in your code attempt.
The next thing is to go through these elements and try and get that
element which contains the href ('VIP Membership').
Code :
listElementsMembership = driver.find_elements_by_css_selector("div[class*='membershipDetail']")
for ele in listElementsMembership:
e = ele.find_element(By.XPATH, ".//descendant::a")
if "VIP Membership" in e.get_attribute('href'):
print(e.text, e.get_attribute('href'))
You can give an index using a square bracket like this.
elemDetailsLink = elem.find_element_by_xpath('(//a[contains(#href,"EditMembership")])[1]')
If you are trying to get an element using XPath, the index should start with 1, not 0.

Identifying an element from a group, span[i] is the differentiating factor

I have added the screenshot I have a group of elements that have the exact same xpath except the span tag.I want to identify the individual input fields, but unable to.
I have tried using contains, with class but unable to attach span to the xpath
Here is what the HTML looks like:
/html/body/div[#id='app']/div/div[#class='LayoutModify_LayoutModify_1Akxb']/main[#class='LayoutModify_main_5aBy3']/section[#class='sub-detail inner ProductDetail_productdetail_bJWN2']/div[#class='ProductDetail_productsphere_kgNGm']/div[#class='ProductDetail_threecol_2zA1n ProductDetail_productsphereleft_2pLZT']/span[4]/div[#class='el-input el-input--medium ProductDetail_productsphereinput_3eVZg']/input[#class='el-input__inner']
/html/body/div[#id='app']/div/div[#class='LayoutModify_LayoutModify_1Akxb']/main[#class='LayoutModify_main_5aBy3']/section[#class='sub-detail inner ProductDetail_productdetail_bJWN2']/div[#class='ProductDetail_productsphere_kgNGm']/div[#class='ProductDetail_threecol_2zA1n ProductDetail_productsphereright_3BrqC']/span[4]/div[#class='el-input el-input--medium ProductDetail_productsphereinput_3eVZg']/input[#class='el-input__inner']
Notice the span[4] and span[15] are the only differences
Quick question:
do either of these locators:
locator A
//span[4]/div/input[#class='el-input__inner']
locator B
//span[15]/div/input[#class='el-input__inner']
find any input on Your page?
If not - could You please post here the whole HTML page code here please?
Here is the xpath that worked:
//div[contains(#class,'ProductDetail_productsphereright')]/span[4]/div/input

how to locate specific node for Xpath on index basis?

I do need to locate second node, on basic of same class available in the Table.
There are six results found on webpage, for query : //td[#class='checkboxCollumn']
If I locate it for second node, By using //td[#class='checkboxCollumn'][2] its giving 0 result.
I have tried some other variations : //td[#class='checkboxCollumn']//i[2] and so on its giving 0 result.
What is the correct way to locate it with index ?
You need to locate like this
(//td[#class='checkboxCollumn'])[2]
Try:
(//td[#class='checkboxCollumn'])[2]
With this:
//td[#class='checkboxCollumn'][2] you trying to match second element within the same container
Use this.. to locate second node...
(//td[#class='checkboxCollumn'])[position()=2]
Here position() is 1-indexed i.e. position will start counting from 1
try using the
(//td[#class='checkboxCollumn'])[2]
as [] has higher priority over //.So rememeber to put the expression is brackets when need to specify the exact node of the selected node-list.
In ur case,it will search for all the elements in the document,that are at the second place.
Even though above thing not work,let me know.

WebDriver not identifying WebElement

I using xpath="//div[#class='localityKewordDropDown']/descendant::div[#class='over']/span[text()='Dwarka, New']
but the element is not getting recognized. NosuchElementException is getting encountered.
Could anyone help me out here.I want to click the drop down value highlighted in the image.
It's failing beacuse there is a space after the word 'New'. The following should work.
//div[#class='localityKewordDropDown']/div/div[text()='Dwarka, New ']
Or consider serarching for the element containing the text rather than matching the entire text.
//div[#class='localityKewordDropDown']/div/div[contains(.,'Dwarka, New')]
And as cathal mentioned, you are searching for a div and not a span.
EDIT:As you request (although I don't believe there is a difference between "descendent" and "//".
//div[#class='localityKewordDropDown']/descendant::div[text()='Dwarka, New ']
//div[#class='localityKewordDropDown']/descendant::div[contains(text(),'Dwarka, New')]
Contains is an xpath function that allows you to query on something containing a value. It can be used with attributes, nodes but it's generally most useful for finding elements containg text. The reason this is working where as your query for the exact string fails is because the element you seek is padded with a trailing space. The contains query will find the element you are seeking as it's ignoring this trailing space.
i dont see anyw spans around your element, try the following:
WebElement name = driver.findElement(By.xpath("//div[#id='keyword_suggest']//div[text()='Dwarka, New']"));
Try this:
WebElement name = driver.findElement(By.xpath("//*[contains(text()='Dwarka, New')]"));

Is there a shorter syntax than soup.select("#visitor_stats")[0]?

I'm using BeautifulSoup (import bs4) to read some information from a web page. Several lines in my script look like
stats = soup.select("#visitor_stats")[0]
Is there a shorter syntax for this?
select() lets you select a bunch of HTML tag elements based on their CSS properties (like id and class). In this case you are looking for all HTML tag elements with CSS id property set to visitor_stats. And then selecting the first element from the returned list.
The BeautifulSoup method find() returns the first occurrence of the search criteria. So the list index [0] can be gotten rid of by using find()
stats = soup.find(attrs={'id':'visitor_stats'})
But I am not sure if this is any shorter :)