Searching for n-th child in n-th parent - selenium

There is a strange behaviour when it comes to finding elements by xpath. The situation:
<body>
...
<div class="ingredients-group">
<div class="group-header">
<h3>Title 1</h3>
... other stuff
</div>
</div>
<div class="ingredients-group">
<div class="group-header">
<h3>Title 2</h3>
... other stuff
</div>
</div>
...
I want to check the text of the H3 tag on the second ingredient-group. So I did the following in Selenium:
WebElement group2 = driver.findElement(By.xpath("//div[#class='ingredients-group'][2]"));
WebElement title2 = group2.findElement(By.xpath("//h3"));
String titleText = title2.GetText();
The last statement returns "Title 1". I would expect it to return "Title 2".
Strangely, this statement returns "Title 2":
String titleText = driver.findElement(By.xpath("//div[#class='ingredients-group'][2]//h3")).getText();
I would like to use the first option (group2.findElement), because there are several other elements in the containers I would like to refer to without having to write the full xpath.
Any ideas on this?
Thanks

Use findElements to return a list of webelements (h3 tags) and then access them as you would any other list:
WebElement groups = driver.findElements(By.xpath("//div[#class='ingredients-group'][2]"));
WebElement theH3Tag = groups[0].findElement(By.xpath(".//h3")); //make this a relative xpath
String titleText = theH3Tag.GetText();
WebElement the2ndH3Tag = groups[1].findElement(By.xpath(".//h3")); //make this a relative xpath
String titleText = the2ndH3Tag.GetText();
Or loop through the list:
WebElement[] groups = driver.findElements(By.xpath("//div[#class='ingredients-group'][2]"));
for (WebElement group : groups) {
WebElement h3Tag = group.findElement(By.xpath(".//h3")); //make this a relative xpath
String titleText = h3Tag.GetText();
}

Related

Scrape text under div tag that is in quotes

Trying to scrape this part: "Lounge, Showers, Lockers"
https://i.stack.imgur.com/k5mzg.png
<div class="CourseAbout-otherFacilities more">
<h3 class="CourseAbout-otherFacilities-title">Available Facilities</h3> " Lounge, Showers, Lockers "
</div>
Website:
https://www.golfadvisor.com/courses/16929-black-at-bethpage-state-park-golf-course
response.css('.CourseAbout-foodAndBeverage.more::text').get() command returns " \n "
Thank you
There are three text elements in your target div (matched by your CSS expression):
<div class="CourseAbout-otherFacilities more">FIRST<h3
<h3 class="CourseAbout-otherFacilities-title">SECOND</h3>
</h3>THIRD</div>
By using .get() you're telling Scrapy to return first match.
I recommend to use XPath expression here instead and match your element by text:
//h3[.="Available Facilities"]/following-sibling::text()[1]'

WebBrowser1 GetElement By name

help use :
WebBrowser1.Document.GetElementById("xxxx").SetAttribute("value", "TESTE")
but I don't have the id, I need to use the name
codigo:
<input class="InputElement is-complete Input" autocomplete="xxxx" autocorrect="off" spellcheck="false" name="xxx" inputmode="numeric" aria-label="xxxx" placeholder="xxxx" aria-placeholder="xxxx" aria-invalid="false" value="xxxx">
Because more than one element can have the same name attribute, getElementsByName will return a node list of all elements with that name.
let x = document.getElementsByName("xxx");
This will set the "value" attribute for all elements with name "xxx".
for (let i = 0; i < x.length; i++) {
x[i].SetAttribute("value", "TESTE");
}
Edit: Sorry I thought you were using javascript.
In VB.net something like this should work
Dim allElements As HtmlElementCollection = WebBrowser1.Document.All
For Each Elem As HtmlElement In allElements
If Elem.GetAttribute("name") = "codigo-date" Then
Elem.SetAttribute("value", "TESTE)
edit: Elem.SetAttribute("value", "TESTE")
End If
Next

how to find element using xpath selenium

Here is my html of my element which i am able to find
<span data-bind="text: myAge()" xpath="1">Showing 1 of 25 people</span>
i could find above element using code like
[FindsBy(How = How.XPath, Using = "//*[#data-bind='text: myAge()']")]
I have another element in Html like which get dynamic ids
<input class="form-control" data-bind="textInput: code, attr: { id: 'myTable_code_' + $index() }" type="text" id="myTable_code_0" >
i tried to find same as above
[FindsBy(How = How.XPath, Using = "//*[#data-bind='textInput: code']")]
But i get error that "It is not able to find element"
How to fix this?
The data-bind attribute is "textInput: code, attr: { id: 'myTable_code_' + $index() }", you need to use all of it
[FindsBy(How = How.XPath, Using = "//*[#data-bind='textInput: code, attr: { id: 'myTable_code_' + $index() }']")]
Or partial attribute
[FindsBy(How = How.XPath, Using = "//*[contains(#data-bind, 'textInput: code')]")]

vb.net get all attributes value using htmlagilitypack

this is the html
<div id="catlist-listview" class="cat-listview cat-listbsize">
<ul>
<li>title1</li>
<li>title2</li>
<li>title3</li>
<li>title4</li>
<li>title5</li>
<li>title6</li>
<li>title7</li>
<li>title8</li>
<li>title9</li>
<li>title10</li>
</ul>
</div>
and my code is
dim htmldoc as new htmldocument
htmldoc.loadhtml(source)
for each link as htmlnode in htmldoc.document.selectnodes("//*[#id='catlist-listview']/ul")
textbox3.text = link.innerhtml
next
the output is
<li>title1</li>
<li>title2</li>
<li>title3</li>
<li>title4</li>
<li>title5</li>
<li>title6</li>
<li>title7</li>
<li>title8</li>
<li>title9</li>
<li>title10</li>
i want get all and only http://wantedlink1 to http://wantedlink10
i try attributes("href") but i get only one link
i want to list all the link like this :
http://wantedlink1
http://wantedlink2
http://wantedlink3
.
.
.
http://wantedlink10
any help ??
Basically, you can change XPath for SelectNodes() to be selecting individual <a> elements instead of <ul>. Then from this point, it will be easy to iterate through the result and get href attribute one by one. Or you achieve the same using LINQ, like the following for example :
'select <a> elements'
Dim links = htmldoc.Document.SelectNodes("//*[#id='catlist-listview']/ul/li/a")
'project to IEnumerable of href attribute value'
Dim hrefs = links.Cast(Of HtmlNode)().Select(Function(x) x.GetAttributeValue("href", ""))
'join the `hrefs`, separated by newline, into one string'
textbox3.text = String.Join(Environment.NewLine, hrefs)
dotnetfiddle demo

i have list items. how to read them all by selenium

<div class="validation-summary-errors" data-valmsg-summary="true">
<ul>
<li>Service User Number must be 6 characters</li>
<li>PSL ID is required</li>
<li>>Bank Account Id (was Credit AccID) is required</li>
<li>Account Name is required</li>
<li>Sort Code is required</li>
<li>Account Number is required</li>
<li>Bank Statement Narrative is required</li>
<li>Company Name is required</li>
<li>Contact Name is required</li>
<li>Email Address is required</li>
<li>Customer Services Phone Number is required</li>
<li>Phone Number is required</li>
<li>Address is required</li>
<li>Reference Number Prefix is required</li>
<li>Report Email Address is required</li>
</ul>
</div>
i want to read all the list and get their values of it. is someone help me as quick as possible. as selenium doesnt recognize unordered tag as it doesnt have name and id anything.....please help..
You can do this like this:
public void test() {
WebElement ul = driver.findElement(By.cssSelector("div.validation-summary-errors ul"));
List<WebElement> lis = ul.findElements(By.tagName("li"));
for (WebElement li : lis) {
// do something with li.getText();
}
}
Why do it in two steps? We can find the li in one selector;
public void test() {
WebElement lis = driver.findElement(By.cssSelector("div.validation-summary-errors ul>li"));
for (WebElement li : lis) {
// do something with li.getText();
}
}
#sircapsalot's answer is good, but I would change the first CSS selector to address OP's requirement "selenium doesnt recognize unordered tag as it doesnt have name and id anything"
public void test() {
WebElement ul = driver.findElement(By.cssSelector("div.validation-summary-errors ul"));
List<WebElement> lis = ul.findElements(By.tagName("li"));
for (WebElement li : lis) {
// do something with li.getText();
}
}
If your SVG data looks like this :
<div id="content-data" class="col-md-12" style="height:666px;">
<svg id="pie-draw-488172" width="492" height="616"><g transform="translate(226,318)">
<text id="pie-text" cursor="default" y="-226" x="241">Compute (227,311)</text>
<text id="pie-text" cursor="default" y="-211" x="241">Database (98,005)</text>
<text id="pie-text" cursor="default" y="-196" x="241">Storage&Content Delivery (69,436)</text>
<text id="pie-text" cursor="default" y="-181" x="241">Networking (30,874)</text>
<text id="pie-text" cursor="default" y="-166" x="241">Other (11,273)</text>
</svg></div>
then use this
public List<IWebElement> content_data = new List<IWebElement>();
content_data = driver.FindElement(By.Id("content-data")).FindElements(By.TagName("text")).ToList();