Why xpath text() node cannot be nested in Scrapy - scrapy

I encounter a problem when playing around xpath selector.
response.xpath('//*[text()="Revenue"]/text()/.')
response.xpath('//*[text()="Revenue"]/text()').xpath('.')
I was expecting two codes above output the same thing. The first one works fine,but the second one returns an empty list.

This is a known issue, there is a feature request to get selectors of text to behave as any other selectors (parsel #130).

Related

How to find the xpath for an element by text containing three dots

I'm trying to find the xpath for an element that contains three dots instead of text. Once I expand the element by clicking on arrow in DOM model html it returns the text.
The following xpath returns nothing unfortunately:
//button[contains(text(),'Pending')]
What's the right solution?
The text content of that element is not a three dots but Pending (). You see the ... only because there is no room to present the text there until you expand the element. So, generally this //button[contains(text(),'Pending')] should work.
You can also try this XPath expression:
//button[contains(.,'Pending')]
It means "a button element with any attribute containing Pending value"
It is more general and should work.
To understand why //button[contains(text(),'Pending')] did not work see this post or this. There are more explanations about this.

How can I find element by non-unique resousre-id?

I test an application which use non-unique resourse-id for elements.
Is there any way to find such elements by xpath like
//*[#resourse-id='non-unique-id'][2]
I mean the second element with same resourse-id.
I'd recommend avoiding xpath in mobile automation since this is the most time-consuming strategy to find elements.
If you don't have any other anchors for your elements but you confident in its order, you can stick to the following approach: Appium driver can return a list of elements with the same locator, in case of Page Object model you can either do this way:
#AndroidFindBy(uiAutomator = "resourceIdMatches(\".*whatever\")")
private List<MobileElement> elements;
so, once your page is initialized, you can access an element by index:
elements.get(1).click();
or, in case of manual managenemt, you can do this way:
List<MobileElement> elements = driver.findElements(MobileBy.AndroidUIAutomator("resoureceIdMatches(\".*whatever\")"));
elements.get(3).click();
Hope this helps.
As far as my understanding goes, you need to select the second element with the path as mentioned: //*[#resourse-id='non-unique-id']
To do that, you need to first grab all the elements with the same non-unique resource ID and then get() them. So, your code should be:
driver.findElements(By.xpath("//*[#resourse-id='non-unique-id']")).get(1).click();
The index for any list starts at 0. So, the second element can be accessed through the value of 1.
Hope this helps.
Try following approach:
(//*[#resourse-id='non-unique-id'])[2]
HTML with non-unique ids is not a valid HTML document.
So, for the sake of future testability, ask the developers to fix the ids.

XPath not found by Selenium but works with jQuery

Given that I have the following XPath:
//table[#title="someTitle"]//td[#id="someId"][3]
When I try to click on this element using WebDriver's element(By.xpath(someXpathString)).click(); I get the "ElementNotFound" exception.
However, when I try finding the element using the SAME XPath but using the console in Chrome DevTools it returns exactly the element that I'm looking for. The call looks like this:
$x('//table[#title="someTitle"]//td[#id="someId"][3]');
Now, I know that if I use THIS XPath:
(//table[#title="someTitle"]//td[#id="someId"])[3]
in WebDriver, the element is found and click works.
Please note that I want to be able to find the 2nd, 3rd or even 4th element by that selector. This is a workaround for interacting with table cells on the same column but different rows.
My question is: why does the Chrome console recognize the element using the XPath without parenthesis while the Find function does not, and what is the actual difference between the two XPaths?
I've noticed on other elements that the parenthesis notation is NOT needed in order to select the 2nd or higher element of that type, so I would like a clear explanation on how this type of XPath works, what is the logic behind it.
Both xpaths are different.
//table[#title="someTitle"]//td[#id="someId"][3] -- will select only 3 column elements
(//table[#title="someTitle"]//td[#id="someId"])[3] -- selects all columns and then returns only one element indexed at 3.
For example assume a table with 4 rows and 4 columns.
First xpath selects only elements in the third column of each row (total 4).
But second xpath slect only one element, ie column number 3 at row 1, irrespective of number rows in the table.
if we use find element, both will return only one element. But if we use find elements, first will return 4 elements but second xpath returns only one element.
If you are going to the page where your element is from another page, try refreshing -
driver.navigate().refresh();

selecting first span value from a group in selenium

I would want to select the first instance of an element in a page where many number of such elements are present with 'ID' which will not be same always.
for example, visit, http://www.sbobet.com/euro which lists lot of sports and odds, where I want to click on the first odds.
and the html structure would be like this,
I want to click on this first span value and proceed with some test case.
Any help on how to achieve this ?
There could be two approaches two the problem:
1. If you are sure you will always need only the first instance:
driver.FindElementsByClassName("OddsR")[0];
If not, then you have collection of elemets and you can access an of those
2. Also, you can first identify any closest enclosing div and then you can use the same snippet as above:
driver.FindElementsByClassName("OddsR")[0];
This one is a better approach if page is a bit dynamic in nature
Use #class attribute. If OddsR class you are intrested in is the 1st one on the page then just use Driver.FindElement(By.ClassName("OddsR")). Webdriver will pick the 1st occurence (no matter if there are more)
Have checked your link and I agree with alecxe, you should probably start with div. But i would suggest a simpler selector :
css = "div.MarketBd span.OddsR"
The above selector will always point to the first span of "OddsR" class within div of "MarketBd" class.
Thanks for the response.
I am finally able to click on the element, by this XPATH,
"//span[#class='OddsR']"
This clicks on the first occurrence of 'OddsR' values, without giving any index.

What's the correct format to extract an attribute from an element of some id using selenium.getAttribute()?

I've tried tracking down the appropriate syntax to extract an attribute using selenium.getAttribute(someXPath), and while I've come across many examples, nothing seems to work. From what I can tell, standard xpath syntax, such as:
//*[#id='someID']
doesn't work. What's the correct format to extract an attribute from an element of some id?
So it seems as if that format is almost correct. The correct string would be
//*[#id="someId"]#someAttribute
Another solution is to use
"someId#someAttribute"
which actually is "better" as the former can generate errors for IE.
Also, it seems that when an element contains no attributes at all, the error message is "attributeValue is null" instead of the normal "Element / attribute not found".