Parsing HTML with xpath or cssSelector? - java

How do I parse for just the text portions of these blocks of code? I am using Selenium client drivers in java.
<li id="NOT_PUT_PREF_STORE" style="">
<span id="STORE_AVAIL" class="BodyLBoldGrey StockStat">Out of stock</span> <span id="InYourLocal">in your local</span> <span id="storeRollover_2"><span id="STORE_CITY" class="BodyLBoldLtgry VIBSStore1">West Hills</span></span> store<span id="notSelectOptionSOI">.</span>
</li>
or
<li id="NOT_PUT_PREF_STORE" style="">
<span id="STORE_AVAIL" class="BodyLLtgry StockStat">Not carried</span> <span class="BodyLLtgry" id="InYourLocal">in your local</span> <span id="storeRollover_2"><span id="STORE_CITY" class="BodyLBoldLtgry VIBSStore1">West Hills</span></span> store<span id="notSelectOptionSOI">.</span>
</li>
or
<li id="NOT_PUT_PREF_STORE" style="">
<span id="STORE_AVAIL" class="BodyMBold StockStatGreen">In stock</span> <span id="InYourLocal">in your local</span> <span id="storeRollover_2"><span id="STORE_CITY" class="BodyLBoldLtgry VIBSStore1">West Hills</span></span> store<span id="notSelectOptionSOI">.</span>
</li>
I am trying to parse for the text portion in each of these variations in the webelement (ie: Not carried, In stock, Out of stock). I am a very new user to selenium and html parsing so this is really hard for me to get functional.
I was thinking that it would be something like
WebElement driver = new FirefoxDriver(profile);
driver.get(Url);
System.out.println(driver.getElement(By.id("STORE_AVAIL").getText());
Not sure how I would do it with cssSelector but people tell me that is faster.
Would this work?
driver.getElement(By.xpath("//li[#id='NOT_PUT_PREF_STORE']./span[#id='STORE_AVAIL']").getText()

When I try to find elements on the page I always build my locators by:
id = driver.getElement(By.id("STORE_AVAIL").getText());
css selector = driver.getElement(By.css("span#STORE_AVAIL").getText());
xpath = driver.getElement(By.xpath("//span[#id='STORE_AVAIL']").getText());
The id seems to be the fastest and easiest, both for webdriver and for me. id should be unique on the page.
CSS take a little more investigative work on my part, but webdriver handles it just fine.
Lastly, xpath is sometimes unavoidable (unless you buy the devs a beer and ask nicely to change to application so you can locate it faster - after all, you are testing for them anyway). Locating by xpath with IE is terribly slow and writing complex xpaths is a drag.
Xpath is also fragile, one small change to the dom can render your xpath unusable. Then you get to debug/rewrite your xpath (it is as fun as it sounds).
My suggestion is to use Firebug and FirePath addons for Firefox to help you craft your locators.

When you 'View Page Source' it will only show the original HTML source. It will not show changes made by AJAX calls, which looks like how the Walmart page is updating that section/element. This question provides a better explanation.
Assuming you are using Firefox (based on the driver you are using), you can go to the page and click Ctrl+Shift+I to bring up the Inspector tool. Select the element you are interested in. Then click the [HTML] button (in the Inspector menu) to view the current source.
Note that when you are getting the element using selenium webdriver, it will be getting the current value rather than the original value seen in the page source. So you do not have to worry about what you see in the page source.

I am tried with the following html code snipet
<li id="NOT_PUT_PREF_STORE" style="">
<span id="STORE_AVAIL" class="BodyLBoldGrey StockStat">Out of stock</span> <span id="InYourLocal">in your local</span> <span id="storeRollover_2"><span id="STORE_CITY" class="BodyLBoldLtgry VIBSStore1">West Hills</span></span> store<span id="notSelectOptionSOI">.</span>
</li>
I am using the following code to solve it. I get the tree of span elements using XPath and parse through each of it to get the text of the elements.
driver.navigate().to("file:///C:/Users/abc/Desktop/test.html");
List<WebElement> spanEle = driver.findElements(By.xpath("//li/span"));
for (int i = 0; i < spanEle.size(); i++) {
System.out.println(spanEle.get(i).getText());

Related

Block an unexpected popup with Selenium

I am automating an e-commerce website but I am getting an unexpected random popup on any page. If I know that a popup will fire on a given web page, I can handle it. What do I do if it randomly occurs on any page?
I know how to block a popup but can't use that in this situation. Due to this popup, my scripts are failing. HTML code:
<div class="acsClassicInner" role="document">
<div class="acsLogoSpacer">
<img src="//gateway.foresee.com/sites/barneys/staging/trigger/sitelogo.gif" class="acsSiteLogo" title="" alt="">
<img src="https://static.foresee.com/logos/foresee/150_67.png" class="acsNoDisplay" title="ForeSee" alt="ForeSee">
<div title="ForeSee" alt="ForeSee" class="acsVendorLogoSVG"></div>
</div>
<h1 id="fsrHeading">We'd welcome your feedback!</h1>
<p>Thank you for visiting Barneys.com. You have been selected to participate in a brief customer satisfaction survey to let us know how we can improve your experience.</p>
<p class="acsNoticeAboutSurvey">The survey is designed to measure your entire experience, please look for it at the <u>conclusion</u> of your visit.</p>
<p class="acsAttribution">This survey is conducted by an independent company ForeSee, on behalf of the site you are visiting.</p>
No, thanks
<a id="acsFocusFirst" tabindex="3" href="about:blank" target="_blank" class="acsInviteButton acsRightButton acsAcceptButton" title="Yes, I'll give feedback (Opens in a new window)" role="button" precog_scanned="true">Yes, I'll give feedback</a>
</div>
Look into EventFiringWebDriver and WebDriverEventListener, and look for the popup in question> lets say the popup occurs after a button click, you can look for it in beforeClickOn and if it does occur do an action, else don't do anything.
Sorry I dont have any Java EventFiringWebDriver code snippets to share
http://seleniumhq.github.io/selenium/docs/api/java/index.html
code from selenium github
from selenium.webdriver import Firefox
from selenium.webdriver.support.events import EventFiringWebDriver, AbstractEventListener
class MyListener(AbstractEventListener):
def before_navigate_to(self, url, driver):
print("Before navigate to %s" % url)
def after_navigate_to(self, url, driver):
print("After navigate to %s" % url)
driver = Firefox()
ef_driver = EventFiringWebDriver(driver, MyListener())
ef_driver.get("http://www.google.co.in/")
Create a helping method with the following pseudo code:-
1. Check if there's a pop up.
2. If it finds pop up, then handle it.
3. If not, then return.
Now use this function in your script every time whenever there's a change in the content on the screen due to some action.

How to select an item from the dropdown list through selenium webdriver and java

Update:
I want to be able to click on the options available example in the HTML code. There are two options (id="all_setup_home" and id="developer-console-link"). Currently, the XPath I am utilizing clicks randomly on the dropdown and it takes me to the option 1 page (that's what i want) but it is not very dynamic as my XPath does not target option 1 or 2 but the drop-down. And so if I want to click on the second option I will not be able to.
Anything better than this would be much appreciated.
The workaround that's working for now:
getElementByXPath("Settings").click();
Thread.sleep(3000);
driver.findElement(By.xpath("//ul[contains(#class,'scrollable')]")).click();
Inital work that is still not working:
<!-- begin snippet: js hide: false console: true babel: false -->
HTML
<div class="popupTargetContainer menu--nubbin-top uiPopupTarget uimenuList uiMenuList--right uimenuList--default visible positioned" data-aura-rendered-by="101:185;a" data-aura-class="uiPopupTarget uimenuList uimenuList--right uimenuList--default" aria-labelledby="59:185;a">
::before
<div role="menu" data-aura-rendered-by="95:184;a">
<!--render facet:96:184;a-->
<ul class="scrollable" role="presentation" data-aura-rendered-by="97:184;a">
<!--render facet: 816:0-->
<!--render facet: 882:0-->
<li class="slds-dropdown__item uiMenuItem onesetupSetupMenuItem" role="presentation" id="all_setup_home" data-aura-rendered-by="893:0" data-aura-class="uiMenuItem onesetupSetupMenuItem">....</li>
<!--render facet:826:0-->
<!--render facet:2004:0-->
<li class="slds-dropdown__item uiMenuItem onesetupSetupMenuItem" role="presentation" id="developer-console-link" data-aura-rendered-by="893:0" data-aura-class="uiMenuItem onesetupSetupMenuItem">....</li>
<!--render facet:826:0-->
<!--render facet:2004:0-->
I had a similar issue, I don't use selenium so I cannot write the code for you but after your dropdown.click(); you have to wait a little moment, cause at the moment you do not wait for the list to be open.
As per your comment as you are able to open the dropdown next as per the HTML you have shared to select an item from the dropdown you have to induce WebDriverWait for the items to render within the HTML DOM and you can use the following code block :
String value = "all-setup_home";
WebElement dropdown = driver.findElement(By.xpath("//span[#class='slds-icon_container slds-icon-utility-setup slds-button__icon slds-global-header__icon']"));
dropdown.click();
List<WebElement> options = new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.xpath("//div[#class='popupTargetContainer menu--nubbin-top uiPopupTarget uimenuList uiMenuList--right uimenuList--default visible positioned']/div[#role='menu']/ul[#class='scrollable']//li[#class='slds-dropdown__item uiMenuItem onesetupSetupMenuItem']")));
for (WebElement option : options)
{
if (option.getAttribute("innerHTML").equals(value))
{
option.click();
break;
}
}
So, I was able to click on the first option getting the XPath from this element:
driver.findElement(By.xpath("//ul[contains(#class,'scrollable')]")).click();
However, this isn't very dynamic as I am unable to click on the second option.

How do I validate n number of <p> tags at runtime?

I have list of <p> tags under a <div> tag and want to validate it all for any changes. The html code is for reference below.
A few of the <p> tags have sub tags and few do not. How do I validate all the <p> tags with their content to an expected value using webdriver?
<div class="content content_login">
<img id="ctl00_MainContent_imgBanner" class="banner" src="../App_Themes/bsi/images/logo/banner_bsi.jpg" style="border-width:0px;">
<p><span id="ctl00_MainContent_lblPageContent"></span></p>
<p><strong>Important Notes: </strong> Welcome to MyLoanWeb.com! If this is your first time visiting our new site, please
enroll for account access. Accounts from loanlink.bsifinancial.com will not be valid unless they are re-enrolled. </p>
<p><strong>If you are experiencing any trouble receiving our emails or clicking on any of the links in the emails, please review our
troubleshooting email issues guide:</strong></p>
<p><strong>Please contact us if you have any questions about our services:</strong></p>
<p>ABC FinCorp Services</p>
<p>P.O. Box 456789</p>
<p>Testville, PA</p>
<p>Customer Care Phone: 800-327-7861 </p>
<p style="padding-bottom:0px;">Customer Care Fax: 814-217-1366</p>
</div>
You don't mention what language you're using, so here's how I would try to do what you're doing in Java:
WebElement parent = driver.findElement(By.cssSelector("div.content.content_login");
List<WebElement> paragraphs = parent.findElements(By.tagName("p"));
As for validating the content of the paragraphs, you'd have to extract the visible text from each of the paragraphs list items and then verify them.
Now, all this assumes that the paragraphs are all child elements of the div and that you're not going to run into any wait issues. You may have to tweak this a bit.
See:
When and how I can locate element by Tagname using selenium webdriver? Please explain with an example

presenceOfAllElementsLocatedBy could not find the element

I am using Selenium and Java to write a test, when I use the code below:
List<WebElement> elements = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy
(By.xpath("//div[.//span[text()='Map']]//*")));
for (WebElement e : elements) {
System.out.println("=>" + e.getTagName() + "<=");
}
it shows all the web elements in that <div> tag.
Result:
=>span<=
=>div<=
=>div<=
=>path<=
=>path<=
=>span<=
As you see, some of the elements tag-name is path but when I use the code below it says that I could not find the element.
List<WebElement> elements = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy
(By.xpath("//div[.//span[text()='Map']]//path")));
It not easy to find the real issue with out knowing your HTML structure.
While I think there is a issue in your xpath
Try below xpath
//div//span[text()='Map']//path
Hope it will help you :)
By.xpath("//div[.//span[text()='Map']]//* will return all the decedents of span[text()='Map'] in the html hierarchy.
For example, this html structure will produce the same results you have
<div>
<span>Map</span>
<div></div>
<div>
<path></path>
<path></path>
</div>
<span></span>
</div>
As you can see, <path> is not <span> direct child, so By.xpath("//div[.//span[text()='Map']]//path is not a valid xpath.
The issue was related to some web elements that Selenium cannot navigate, the web element that I was trying to catch was inside a svg web element which is not detectable by Selenium have a look here this is exactly what was happening to me.

Get xpath of div having multiple occurence in page

I am having a weird requirement. I am having a div class named "expandThisSection". And I have
<div id=​"requiredAccessoriesContentPlaceHolder" class=​"expandThisSection">​No required accessories are available for this product.​</div>​
<div id=​"requiredAccessoriesContentPlaceHolderMeasurement" class=​"expandThisSection">​ ​</div>​
<div id=​"optionalAccessoriesContentPlaceHolder" class=​"expandThisSection">​No optional accessories are available for this product.​</div>​
<div id=​"optionalAccessoriesContentPlaceHolderMeasurement" class=​"expandThisSection">​ ​</div>​
<div class=​"expandThisSection">​
<div style=​"width:​95%">​mytext</div>​
​<ul class=​"movePos">​…​</ul>​
<div><b>test</b>​</div>
​<div>​<b>abc</b> Get this text</div>
​<div id=​"vendLogo">​…​</div>
</div>
<div class="expandThisSection">
<table>...</table>
</div>
I want the content of the div that has style of 95% width.That is value I want is "mytext". But I am not able to find out xpath for the same.
Also I want xpath for finding the div content just above div with id=​"vendLogo". That is I want "Get this text".
NOTE: ITS ASSURED THAT THIS Bold tag WILL CONTAIN "abc"
How to do it? I am using selenium with Java
Got the first one. Not able to get second one.
Code:
List<WebElement> currentSkuDescription = driver.findElements(By.xpath("//div[#class='expandThisSection']/div"));
for(WebElement currentItem: currentSkuDescription) {
WebElement descriptionBlock = currentItem.findElement(By.xpath("//div[contains(#style, 'width:95%')]"));
description= descriptionBlock.getText();
}
Try dropping the #class='expandThisSection' because the div you want does not have that class attribute (it's parent does). Also, an exact match may be possible.
By.xpath("//div[#style='width:95%']
By.xpath("//div[contains(#style, 'width:95%')]
Either of those should work. If you want to make sure you are grabbing the right one, relative to the parent, use XPath axes...
//div[contains(#class, 'expandThisSection')]/child::div[contains(#style, 'width:95%')]
If you to search for the div by a specific text (in this case 'mytext') this you can use this xpath:
"//div[text()[contains(.,'mytext')]]/ancestor::div[#class='expandThisSection']"
Or if you want by the styling, the you can use this xpath:
"//div[#style='width:95%']/ancestor::div[#class='expandThisSection']"
Note that the second xpath will only work where the inline styling is done on the tag.
For the second query, try this xpath:
"//div[#id='vendLogo']/preceding-sibling::div[1]"
To get the specific text you require, you can do the following:
String text = driver.findElement(By.xpath("//div[#id='vendLogo']/preceding-sibling::div[1]")).getText();
text.replace(div.findElement(By.tagName("b")).getText(), "");

Categories

Resources