I'm trying to get the number of followers on twitter. I successfully managed to get number of followers like so:
String followers = driver.findElement(By.xpath("//div[#class='ProfileCanopy-navBar']//li[#class='ProfileNav-item ProfileNav-item--followers']//span[#class='ProfileNav-value']")).getText();
The problem is that the answer is not the exact number, "4.41M".
The HTML:
<a class="ProfileNav-stat ProfileNav-stat--link u-borderUserColor u-textCenter js-tooltip js-nav" data-nav="followers" tabindex="0" data-original-title="4,406,048 Followers">
<span class="ProfileNav-label">Followers</span>
<span class="ProfileNav-value" data-is-compact="true">4.41M</span>
</a>
I'm trying to get the number "4,406,048" (at the end of attribute a). I looked online for about an hour and didn't find a proper solution. I'm using Selenium with Java and Chrome.
This was a strange one. I wrote code that should have pulled the number but it kept returning null also. I finally figured out what was going on when I pulled the element and then wrote out the outerHTML. The element was being changed during page load.
WebDriver driver = new FirefoxDriver();
driver.get("https://twitter.com/blakeshelton");
WebDriverWait wait = new WebDriverWait(driver, 5);
WebElement e = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("a[data-nav='followers']")));
System.out.println(e.getAttribute("outerHTML"));
System.out.println(e.getAttribute("title"));
If you run this code you will get
<a class="ProfileNav-stat ProfileNav-stat--link u-borderUserColor u-textCenter js-tooltip js-openSignupDialog js-nonNavigable u-textUserColor" title="14,189,678 Followers" data-nav="followers" href="/blakeshelton/followers">
<span class="ProfileNav-label">Followers</span>
<span class="ProfileNav-value" data-is-compact="true">14.2M</span>
</a>
14,189,678 Followers
You will notice in the A tag in the outerHTML that title contains the number of followers. That's why I'm using it instead of data-original-title. Anyway, this code has been tested and it works.
Since you reference Selenium, this is where you use getAttribute() to return the value of a given attribute. In this case we want the value of 'data-original-title'.
driver.findElement(By.cssSelector("[data-nav='followers']")).getAttribute("data-original-title");
Then, since this returns more data than you desire (x followers), you strip out the non-numerics with some Java:
replaceAll("[$A-Za-z , ]", "");
So put together it looks something like this:
String followers = driver.findElement(By.cssSelector("[data-nav='followers']"))
.getAttribute("data-original-title").replaceAll("[$A-Za-z , ]", "");
You were using getText() which returns the inner text of an element. GetAttribute() returns value of an attribute, which in this case is data-original-title.
Here's the code I used to confirm it works on the HTML you provided.
public static void main(String[] args)
{
ChromeDriver driver = new ChromeDriver();
driver.get("file:///C:/Users/myId/Downloads/stack.html");
String followers = driver.findElement(By.cssSelector("[data-nav='followers']"))
.getAttribute("data-original-title").replaceAll("[$A-Za-z , ]", "");
System.out.println(followers);
}
you can test that in chrome using the inspection tools and then testing your xpath.
You should be doing something like that:
$x("//a[#data-nav='followers']/#data-original-title")
This got me
[data-original-title="1,880,556 Followers"]
From there just evaluate in Java.
Related
I am attempting to run a selenium script which will return the text displayed on the screen after a user input into a dynamic search field.
I am able to enter the text and see the results on screen but my Javascript to output the text does not work as the ID field I am using is dynamic.
I am trying to get the text to display in the Browser Console so I can use that in my Javascript. If I try by ID but use the dynamically assigned ID then I get the appropriate return, however, the next time the page refreshes that ID will no longer be valid.
The HTML is as follows:
<input
type="text"
id="origin-29890"
name="origin"
class="ej-input origin ui-autocomplete-input"
required=""
aria-label="From Airport"
data-routesearch-placeholder="e.g. London Gatwick"
aria-describedby="route-search-origin-description"
aria-autocomplete="list"
aria-expanded="false"
autocomplete="off"
aria-owns="ui-id-1"
placeholder="e.g. London Gatwick"
aria-activedescendant="selected-autocomplete-item">
If I try to use getElementsByClassName instead then on running that in the browser console I don't get what I'm looking for;
"f values() { [native code] }
If the field was static then the following would work
String script = "return document.getElementById(\"origin\").value";
String text= (String) jse.executeScript(script);
System.out.println(text);
I'm looking for a way of either changing the return document line to use a dynamic id or showever make the script accept the Xpath so I can include a starts with tag
You can locate the element using XPath locator like:
WebElement myInput = driver.findElement(By.xpath("//input[#name='origin']"));
once done you can get its id attribute:
System.out.println(myInput.getAttribute("id"));
or if you want you can obtain the value attribute via JavaScriptExecutor like:
System.out.println(driver.executeScript("return [0].value", myInput));
I think you can find it by name. Please try this:
String script = "return document.getElementsByName(\"origin\").value";
Here is what I'm trying to do:
I have some links on a webpage with this pattern:
/html/body/div[4]/div/div/section/div[2]/div[3]/div/div1/div1/div/div[2]/a
/html/body/div[4]/div/div/section/div[2]/div[3]/div/div1/div[2]/div/div[2]/a
/html/body/div[4]/div/div/section/div[2]/div[3]/div/div1/div[3]/div/div[2]/a
/html/body/div[4]/div/div/section/div[2]/div[3]/div/div1/div[4]/div/div[2]/a
However, I also have other links within the same web page that have a similar path but not exactly following the same pattern:
/html/body/div[4]/div/div/section/div[2]/div[3]/div/div[3]/div/div1/div1/div/div[2]/a
How can I get just the links which follow the first pattern displayed and ignore the other ones?
Ps: I'm using Selenium Webdriver and Java and this is the update question with the html for the links
<div class="col-sm-6 half-tile">
<div class="outside-caro">
<div class="grey-overlay">
<div class="inside-caro" style="background-image:url(' https://resources/images/metabolism.jpg'")>
</div>
</div>
<div class="tile-content">
<h4 class="module title-long-card">Healthy Weight Loss</h4>
<p class="module line-clamp">This online eLearning programme is designed to help you make smart decisions when it comes to dieting and to be aware of the pitfalls.</p>
<a class="more-button" href="/application/res-courses/overview?id=23">Learn More<i style="font-size: 10px;padding-left: 5px; "class="fa fa-chevron-right" aria-hidden="true"></i></a>
</div>
</div>
</div>
Thanks very much.
I'm not quite following what you're really hoping for from your description, but I can make some guesses.
The quick answer is, just always give the full path.
But there are ways to make things a little easier to code. There are a couple ways you can create a pointer on the page and to only look for things beyond that point. The most straightforward is using simple string concatenation:
String pointer = "/html/body/div[4]/div/div/section/div[2]/div[3]/div/div[1]";
WebElement tag1 = driver.findElement(By.xpath(pointer + "/div[1]/div/div[2]/a"));
WebElement tag2 = driver.findElement(By.xpath(pointer + "/div[2]/div/div[2]/a"));
The other is to declare that pointer as a WebElement, and then use it as a base for all future findElements:
WebElement pointer = driver.findElement(By.xpath("/html/body/div[4]/div/div/section/div[2]/div[3]/div/div[1]"));
WebElement tag1 = pointer.findElement(By.xpath("./div[1]/div/div[2]/a"));
WebElement tag2 = pointer.findElement(By.xpath("./div[2]/div/div[2]/a"));
Note the dot at the beginning of the xpath to say "Use this node as your starting point".
Now, what I think you're really trying to accomplish to to make a list of all the anchors, not just pick them one by one. As in "get all the link that match one pattern but not a different but similar pattern". For that, you could just do a variation of either of the two above methods. For instance:
WebElement pointer = driver.findElement(By.xpath("/html/body/div[4]/div/div/section/div[2]/div[3]/div/div[1]"));
List<WebElement> tags = pointer.findElement(By.xpath("./div/div/div[2]/a"));
This will pull in all the links that match the pattern into a List. There are a couple things to take note:
The first element is just div, not div[1] and div[2]. since that seems to be the only thing changing in the pattern.
Most likely, the language you will use to script this is 0-indexed. So div[1] is tags.get(0).
I have a solution to problem and i hope it will help you.
You just have to identify a single parent for all 4 links that you mentioned above. And i feel you can use this locator as parent node /html/body/div[4]/div/div/section/div[2]/div[3]/div/div[1]/div[1].
Please find my code..
System.setProperty("webdriver.chrome.driver","Drivers/chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("http://www.abodeqa.com/2015/08/26/finding-child-elements-in-webdriver-using-findelements/");
Thread.sleep(3000);
WebElement parent = driver.findElement(By.xpath("//section[#class='secondary clearfix']"));
List<WebElement>childernNodes = parent.findElements(By.xpath("./aside//a"));
System.out.println("Total: "+childernNodes.size());
for(WebElement value: childernNodes){
System.out.println(value.getAttribute("href"));
}
WebElement pointer = driver.findElement(By.xpath("/html/body/div[4]/div/div/section/div[2]/div[3]/div/div[1]"));
// Generic path to simulate the change in the xpath for the elements of the following pattern:
// WebElement tag1 = pointer.findElement(By.xpath("./div[1]/div/div[2]/a"));
// WebElement tag2 = pointer.findElement(By.xpath("./div[2]/div/div[2]/a"));
List<WebElement> linksList = pointer.findElements(By.xpath("./div/div/div[2]/a"));
for (WebElement link : linksList) {
System.out.println(link.getAttribute("href"));
}
I have the following html tag and I want to receive "name":"test_1476979972086" from my Java Selenium code.
How can I achive this?
I already tried getText and getAttribute function but without any success.
<a data-ng-href="#/devices"
target="_blank"
class="ng-binding"
href="#/devices">
{"name":"test_1476979972086"}
</a>
getText() is always emtpy. The xpath is unique. newDevice.created is unique on page.
final By successMessageBy = By.xpath("//p[#data-ng-show='newDevice.created']/a");
final WebElement successMessage = wait.until(ExpectedConditions.presenceOfElementLocated(successMessageBy));
final String msg = successMessage.getText();
Actually WebElement#getText() returns only visible text. It could be possible element is present there but text would be visible later.
So if WebElement#getText() doesn't work as expected, you should try using getAttribute("textContent") as below:-
successMessage.getAttribute("textContent");
upon first glance, the below should work. the fact that what you've tried doesnt work, leads me to believe that you aren't selecting the correct element. since i am ignorant of the rest of your html, this might not be unique. you'll have to play around with it, or share the surrounding html
String json = driver.findElement(By.cssSelector("a[href$='/devices']")).getText()
Edit :
The element was inside an iframe, this is how it finally worked:
WebDriverWait wait = new WebDriverWait(_driver, 60);
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By
.xpath("//*[#class='IFrameID']")));
WebElement element_t = _driver.findElement(
By.xpath("//*[#myattribute='mytest']"));
Edit :
My problem seems to be the structure of the page. i tried different things, and i only was able to get the body by id, ever other element i tried to get by id or any other attribute couldnt be found...
I am trying to get an element by using the By.xpath method, the xpath itself works just fine when used in firebug/firepath, but when used in the java application i am getting an Exception:
org.openqa.selenium.NoSuchElementException: Unable to locate element: {"method":"xpath","selector":".//*[#myattribute='mytest']"}
The attribute i am trying to access is not a standard html one, but generated from a framework so the field looks like this :
<input id="F_19" class="FIELDInputEdit" type="text" style=" width:100%;" maxlength="40" myattribute="mytest" name="CC">
The javacode itself looks like this :
WebElement element_t = _driver.findElement(
By.xpath(".//*[#myattribute='mytest']"));
Since the only known attribute is this one, i have no ohter way to access the input field.
I am using Firefox 17.0.11
good practice (imho) before using xpath in webdriver test it using selenium ide (http://docs.seleniumhq.org/download/)
Error might be because of «.» before «//». Try to remove it.
Read this: http://www.w3schools.com/xpath/xpath_syntax.asp
.//*[#myattribute='mytest']
«.» = Selects the current node
«//» = Selects nodes in the document from the current node that match the selection no matter where they are
«*» = Matches any element node
«[#myattribute='mytest']» ( = [#myattribute = \"mytest\"]) = Node, that contains attribute "myattribute", which value is "mytest"
Now, _driver.findElement(By.xpath("//*[#myattribute='mytest']")) = search whole page for first node with attribute «myattribute» with value «mytest»
_driver.findElement(By.xpath("//input[#myattribute='mytest']"))
= search whole page for first input with «myattribute» = «mytest»
_driver.findElement(By.xpath("//input[#myattribute='mytest']")).then(By.path("./*[#comeAtr]")) = in input with «myattribute» = «mytest» find any node with atribute = «
Have you tried to use CSS selectors instead?
By.cssSelector("input[myattribute=\"mytest\"]")
The element was inside an iframe, this is how it finally worked:
WebDriverWait wait = new WebDriverWait(_driver, 60);
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By
.xpath("//*[#class='IFrameID']")));
WebElement element_t = _driver.findElement(
By.xpath("//*[#myattribute='mytest']"));
In the frame I'm working with, I have the following element:
<div class="x-grid3-cell-inner x-grid3-col-expRepCol"> New session from client IP 192.168.5.3 (ST=/CC=/C=) at VIP 192.168.5.2 Listener /Common/Tomcat (Reputation=Unknown)</div>
As well as many other similar elements. I am trying to locate this element by partial name text and click it with the following code:
String expectedText = "New session from client IP";
driver.findElement(By.className("div[class*='"+expectedText+"']")).click();
And I have also tried with cssSelector:
String expectedText = "New session from client IP";
driver.findElement(By.cssSelector("div[class*='"+expectedText+"']")).click();
But WebDriver keeps throwing an exception stating it's unable to locate that element. Any suggestions as to what could be the problem?
<div class="dd algo algo-sr Sr" data-937="5d1abd07c5a33">
<div class="dd algo algo-sr fst Sr" data-0ab="5d1abd837d907">
Above 2 are the HTML elements in yahoo search results. So if we wanna get these elements using partial class name with selenium python, here is the solution.
driver.find_element_by_css_selector("div[class^='dd algo algo-sr']")
In the same way we can get any elements with partial match on any attribute values like class name, id etc.
find elements with css selector partial match on attribute values
By.className is looking for a class with the name entered.
By.cssSelector is looking for a match for the selector you entered.
What you're attempting is to match the text of the div against class, which won't work.
You can try something like this:
driver.findElement(By.xpath("//div[contains(text(),'"+expectedText+"')]")).click();
I believe this will work:
driver.findElement(By.className("x-grid3-cell-inner x-grid3-col-expRepCol").click();