I am automating extracting product variations on Amazon and I have the following HTML markup:
<ul
class="a-nostyle a-button-list a-horizontal a-spacing-top-micro swatches swatchesSquare imageSwatches">
<!-- Please note that in className never append a class with prefix as 'swatch'. It would break something in the twister JS -->
<li id="color_name_0" class="swatchSelect" data-dp-url="" title="Click to select White">
<span class="a-list-item">
<div class="tooltip">
<span class="a-declarative" data-swatchthumb-action="{"dimIndex":1,"dimValueIndex":0}" data-action="swatchthumb-action">
<span id="a-autoid-11" class="a-button a-button-thumbnail a-button-toggle">
<span class="a-button-inner">
<button id="a-autoid-11-announce" class="a-button-text" type="button">
<span class="xoverlay" />
<div class="">
<div class="">
<img style="height:36px; width:36px" alt="White"
src="http://ecx.images-amazon.com/images/I/41IrdkWxWOL._SS36_.jpg"/>
</div>
<div class="" style=" " />
</div>
</button>
</span>
</span>
</span>
</div>
</span>
</li>
</ul>
I'm using the following XPath to extract the XPath of all colors.
.//*[#id='variation_color_name']/ul/li/span/div/span/span/span/button
Now I want to extract the alt attribute of each item but when I try using getAttribute("alt") it does not return anything. In this case the alt text would be "White". The product I am viewing is: http://www.amazon.com/dp/B00J46VVKE . I'm using Java.
When you have an id attribute there is no need to go to xpath's i believe, unless you have many button's with same id. However here's how you can get the attribute of the img element -
WebElement btn = driver.findElement(By.id("a-autoid-11-announce"));
String imgColor = btn.findElement(By.tagName("img")).getAttribute("alt");
Hope this helps.
You can use this code:
public class Stackoverflow extends Init {
#Test
public void testToGetAltAttribute() throws InterruptedException {
System.out.println("Get Attribute....");
// this element has alt attribute hence that will be displayed.
assertAndVerifyElement(By.cssSelector("#landingImage"));
System.out.println("\n#landingImage\n=====================");
System.out.println(getAttributeOfGivenElement(By.cssSelector("#landingImage"), "alt"));
// this element do not has alt attribute hence that will not be
// displayed.
// it will display msg "element do not have altattribute"
assertAndVerifyElement(By.id("productTitle"));
System.out.println("\n#productTitle\n=====================");
System.out.println(getAttributeOfGivenElement(By.id("productTitle"), "alt"));
}
public String getAttributeOfGivenElement(By element, String attributeName) {
WebElement webElement = getWebDriver().findElement(element);
if (webElement.getAttribute(attributeName) != null) {
return webElement.getAttribute("alt");
} else {
return "element do not have " + attributeName + "attribute";
}
}
public void assertAndVerifyElement(By element) throws InterruptedException {
boolean isPresent = false;
for (int i = 0; i < 5; i++) {
try {
if (getWebDriver().findElement(element) != null) {
isPresent = true;
break;
}
} catch (Exception e) {
// System.out.println(e.getLocalizedMessage());
Thread.sleep(1000);
}
}
Assert.assertTrue(isPresent, "\"" + element + "\" is not present.");
}
}
If you want all the colors, you will want to grab the IMG elements that contain the ALT attribute. Your XPath ends at a BUTTON. Try the code below.
List<WebElement> colors = driver.findElements(By.cssSelector("ul.imageSwatches img"));
for (WebElement color : colors)
{
System.out.println(color.getAttribute("alt"));
}
The CSS selector is read find a UL tag that has the class imageSwatches then find all descendant IMG tags. You loop through that collection of IMG tags and output the ALT text.
Related
i am trying to display two "text text-pass" from html in chrome browser to my print console, apparently, it did not work, any advise please?
my browser html code
<a href="/abc/123" class="active">
<div class="sidebar-text">
<span class="text text-pass"> </span> </a>
<a href="/abc/1234" class="active">
<div class="sidebar-text">
<span class="text text-pass"> </span> </a>
My code
String 123= driver.findElement(By.xpath("//*[#id="js-app"]/div/div/div[2]/div[1]/div/div/ul/li[5]/a")).getText();
System.out.println(123);
String 1234= driver.findElement(By.xpath("//*[#id="js-app"]/div/div/div[2]/div[1]/div/div/ul/li[5]/a")).getText();
System.out.println(1234);
You can use .findElements to get multiple elements with the same pattern, it will return a list collection.
UPDATE
Refers to your comment, you need put the string into a list again and check with the Collection.contains() method:
List<String> results = new ArrayList<>();
List<WebElement> elements = driver.findElements(By.xpath("//div[#class='sidebar-text']//span"));
for(WebElement element: elements) {
String attr = element.getAttribute("class");
results.add(attr);
System.out.println(attr);
}
if(results.contains("text text-fail")) {
System.out.println("this is list contains 'text text-fail'");
}
Try this Code :
String pass = driver.findElement(By.xpath("//*[#class='sidebar-text']/span")).getAttribute("class");
System.out.println(pass);
There is a switch-on/switch-off element on a Web Page. And underneath, here is the source code defined:
<div class = "button">
<label class = "switch">
<input id="sim-switch" class = "hidden" type="checkbox">
<div class = "slider clearfix">
::before
<div class="on-text pull-left">ON</div>
<div class="off-text pull-left">OFF<div>
<div class="inner-slider"></div>
::after
</div>
</label>
</div>
And if was to put this step into selenium automation, I am not sure which part is the "click()" area to make this switch happen. Any ideas?
You can use checkbox for operation, first locate element and use the isChecked() method with if else conditions for operations:
WebElement ele= driver.findElement(By.id("sim-switch"));
if(ele.isSelected()==true)
{
System.out.println("it is clicked");
//append your operations
}
else
{
ele.click();
System.out.println("it is now clicked");
//append your operations
}
So I'm having trouble figuring out how to manipulate the data completely that I'm scraping using Jsoup. I know how to target the areas but i don't know how to target them individually but still group them together.
For Example:
<div class="panel panel-default">
<div class="panel-heading">
<p> Heading1 </p>
</div>
<div class="panel-body">
<p> Body1 <p>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<p> Heading2 </p>
</div>
<div class="panel-body">
<p> Body2 <p>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<p> Heading3 </p>
</div>
<div class="panel-body">
<p> Body3 <p>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<p> Heading4 </p>
</div>
<div class="panel-body">
<p> Body4 <p>
</div>
I want to target different sections in this HTML and then place them in textViews a certain way. But when I try to for example target div.panel-heading & div.panel-body and I want to place the heading above the body it will repeat all of the div.panel-headings for the entire page first then below that it will repeat all of the div.panel-bodys. It's printing them in totally separate groups instead of one on top of the other.
Below is the code I'm using:
private void arbitrage() {
new Thread(new Runnable() {
#Override
public void run() {
final StringBuilder builder = new StringBuilder();
final StringBuilder builder2 = new StringBuilder();
try {
Document doc = Jsoup.connect("THE URL HERE").get();
Elements links = doc.select("div.panel.panel-default > div.panel-heading");
Elements links2 = doc.select("div.panel.panel-default > div.panel-body");
for (Element link : links) {
builder.append("\n").append(link.text());
builder2.append("\n").append(links2.text() + "\n");
}
} catch (IOException e) {
builder.append("Error : ").append(e.getMessage()).append("\n");
}
runOnUiThread(new Runnable() {
#Override
public void run() {
arbitrage.setText(builder.toString() + builder2.toString());
}
});
}
}).start();
}
==-=-=-=-=-=- EDITED =-=-=-=-=--
I've changed the HTML code to better reflect what the web URL looks like. When I run my current code it displays.
Heading1
Heading2
Heading3
Heading4
Body1
Body2
Body3
Body4
I want it to display as follows.
Heading1
Body1
Heading2
Body2
Heading3
Body3
Heading4
Body4
So essentially, I want to grab the panel-heading & panel-body individually, but display them together in a group. I can grab them both in one group by selecting div.panel.panel-default, but I don't have as much control on how this is displayed from a UI standpoint. At least I don't know how to manipulate that data when I scrape it all together like that.
EDIT TWO =-=-=-=-=-=-=-=-
I'm getting close, this code allows me to manipulate the data individually better, but still cant do what I need. I want to style the heading & body let's say different colors. I can't figure this out.
for (Element panel : panels) {
Elements links = panel.select("div.panel-heading");
Elements links2 = panel.select("div.panel-body");
builder.append("\n").append(links.text()).append("\n").append("\n").append(links2.text())
.append("\n")
.append("\n");
}
changed my runOnUIThread to this:
runOnUiThread(new Runnable() {
#Override
public void run() {
arbitrageTextView.setText(builder.toString());
}
});
But if I want to like change the text color for the header different from the body I'm not able to. Or add a divider between all of the groups, doesn't allow me to do this. It just seems very limited on the UI side of things, doesn't allow me to stylize them, just pull them in and display them. I believe this is because it's pulling it all in under one textView, would I need to put them in two different textViews?
Try this:
Elements panels = doc.select("div.panel.panel-default");
for (Element panel : panels) {
Elements links = panel.select("div.panel-heading");
Elements links2 = panel.select("div.panel-body");
builder.append("\n").append(links.text());
builder.append("\n").append(links2.text() + "\n");
}
Update
I changed code
I am having trouble with clicking at an element of a menu which is written like this:
<div class="menu">
<ul class="tabs ctrlTabsProfile">
<li class="active" data-tab="tabDetail">User Details</li>
<li data-tab="tabEmail">Email</li>
<li data-tab="tabPass">Change password</li>
<li data-tab="tabAdress">Account Details</li>
</ul>
</div>
I have tried these:
driver.findElement(By.linkText("Account Details")).click();
driver.findElement(By.cssSelector("li[data-tab=tabAdress")).click();
driver.findElement(By.xpath("li[data-tab='tabAdress']")).click();
also tried listing the elements but got null only :
for(WebElement el : driver.findElements(By.cssSelector(".tabs.ctrlTabsProfile"))) {
try {
assertTrue(driver.findElement(By.cssSelector("BODY")).getText().matches("^[\\s\\S]*Account Details[\\s\\S]*$"));
} catch (Error e) {
System.out.println("Not found: \"Account Details\".");
}
String s = el.getAttribute("data-tab");
System.out.println(s);
if(s.equals("tabAdress")) {
driver.findElement(By.xpath("li[data-tab='tabAdress']")).click();
}
}
Solutions? Sugestions? Errors?
Well, for one, your xpath selector is incorrect.
driver.findElement(By.xpath("li[data-tab='tabAdress']")).click();
should be:
driver.findElement(By.xpath("//li[#data-tab='tabAdress']")).click();
edit:
And your css selector is incorrect as well.
driver.findElement(By.cssSelector("li[data-tab=tabAdress")).click();
should be:
driver.findElement(By.cssSelector("li[data-tab='tabAdress']")).click();
edit #2:
and:
driver.findElement(By.linkText("Account Details")).click();
will only work if the element is a link, which in this case it is not.
Aholt is right, driver.findElements(By.cssSelector(".tabs.ctrlTabsProfile")) will return only ul elements. To access all <li>, you could try:
driver.findElements(By.cssSelector("ul.tabs.ctrlTabsProfile li.active"))
Is there any way I can get the properties of an element on which I place the cursor on? I will be using a JavaFX browser to load the websites. So I cannot use firebug or any plugins. Is there any possibility to achieve this? Please help.
Its just like Inspect Element in Firebug.
In JavaScript, when this "choose an element" mode is activated, you can attach a mouseover handler to the document. This will receive repeated calls as the mouse moves over elements. You can tell which element the mouse is over via the target property on the event object, e.g.:
document.addEventListener("mouseover", function(e) {
// Use e.target to know which element it is
}, false);
Then simply look at the element. You might also hook mouseout to know when you leave an element.
There are limits to this. For instance, you can't get a list of event handlers attached to it through a normal DOM API.
Here's a simple example demonstrating the handler:
var lastElement = null;
var display = document.getElementById("display");
document.addEventListener("mouseover", function(e) {
if (e.target != lastElement) {
lastElement = e.target;
show("tag", lastElement.tagName);
show("id", lastElement.id);
show("name", lastElement.name);
show("class", lastElement.className);
show("style-color", lastElement.style.color);
show("computed-color", getComputedStyle(lastElement).color);
}
}, false);
document.addEventListener("mouseout", function(e) {
var n, list;
if (e.target == lastElement) {
list = display.querySelector("span");
for (n = 0; n < list.length; ++n) {
list[n].innerHTML = "";
}
lastElement = null;
}
}, false);
function show(type, text) {
display.querySelector("." + type).innerHTML = text;
}
.foo {
color: green;
}
<p id="main-paragraph">
This is a test, with
<strong class="foo">various elements</strong>
that you can
<em style="color: blue">mouse over</em>.
<input type="text" name="the-input">
</p>
<div id="display">
<div>tag: <span class="tag"></span></div>
<div>id: <span class="id"></span></div>
<div>name: <span class="name"></span></div>
<div>class: <span class="class"></span></div>
<div>style.color: <span class="style-color"></span></div>
<div>computedStyle.color: <span class="computed-color"></span></div>
</div>