Alii
Alii

Reputation: 85

How to get Dynamic Xpath of a webtable?

List<WebElement>table=driver.findElements(By.xpath("//*[@id=\"prodDetails\"]/div[2]/div[1]/div/div[2]/div/div/table/tbody/tr"));
JavascriptExecutor jse = (JavascriptExecutor) driver;
// jse.executeScript("arguments[0].scrollIntoView();",table);
jse.executeScript("arguments[0].style.border='3px solid red'",table);
int row= table.size();

I am unable to get the required no of row and column.The xpath i provided does not find the table on site

Link : Click here

I have to fetch the specification of the mobile.

Upvotes: 1

Views: 1837

Answers (4)

Jeronimo Backes
Jeronimo Backes

Reputation: 6289

XPATH can be pretty hard to read, especially when you need to use it a lot.

You could try the univocity-html-parser

    HtmlElement e = HtmlParser.parseTree(new UrlReaderProvider("your_url"));

    List<HtmlElement> rows = e.query()
            .match("div").precededBy("div").withExactText("Technical Details")
            .match("tr").getElements();

    for(HtmlElement row : rows){
        System.out.println(row.text());
    }

The above code will print out:

    OS Android
    RAM 2 GB
    Item Weight 150 g
    Product Dimensions 7.2 x 14.2 x 0.9 cm
    Batteries: 1 AA batteries required. (included)
    Item model number G-550FY
    Wireless communication technologies Bluetooth, WiFi Hotspot
    Connectivity technologies GSM, (850/900/1800/1900 MHz), 4G LTE, (2300/2100/1900/1800/850/900 MHz)
    Special features Dual SIM, GPS, Music Player, Video Player, FM Radio, Accelerometer, Proximity sensor, E-mail
    Other camera features 8MP primary & 5MP front
    Form factor Touchscreen Phone
    Weight 150 Grams
    Colour Gold
    Battery Power Rating 2600
    Whats in the box Handset, Travel Adaptor, USB Cable and User Guide

Alternatively the following code is a bit more usable, as I believe you probably want more stuff from that page too, and getting rows with data is usually what you want to end up with:

    HtmlEntityList entityList = new HtmlEntityList();
    HtmlEntitySettings product = entityList.configureEntity("product");

    PartialPath technicalDetailRows = product.newPath()
            .match("div").precededBy("div").withExactText("Technical Details")
            .match("tr");

    technicalDetailRows.addField("technical_detail_field").matchFirst("td").classes("label").getText();
    technicalDetailRows.addField("technical_detail_value").matchLast("td").classes("value").getText();

    HtmlParserResult results =  new HtmlParser(entityList).parse(new UrlReaderProvider("your_url")).get("product");

    System.out.println("-- " + Arrays.toString(results.getHeaders())  + " --");
    for(String[] row : results.getRows()){
        System.out.println(Arrays.toString(row));
    }

Now this produces:

    OS = Android
    RAM = 2 GB
    Item Weight = 150 g
    Product Dimensions = 7.2 x 14.2 x 0.9 cm
    Batteries: = 1 AA batteries required. (included)
    Item model number = G-550FY
    Wireless communication technologies = Bluetooth, WiFi Hotspot
    Connectivity technologies = GSM, (850/900/1800/1900 MHz), 4G LTE, (2300/2100/1900/1800/850/900 MHz)
    Special features = Dual SIM, GPS, Music Player, Video Player, FM Radio, Accelerometer, Proximity sensor, E-mail
    Other camera features = 8MP primary & 5MP front
    Form factor = Touchscreen Phone
    Weight = 150 Grams
    Colour = Gold
    Battery Power Rating = 2600
    Whats in the box = Handset, Travel Adaptor, USB Cable and User Guide

Disclosure: I'm the author of this library. It's commercial closed source but it can save you a lot of development time.

Upvotes: 0

Subburaj
Subburaj

Reputation: 2334

You can get the total no of rows using the below Xpath.

In the above link, we are having multiple section which has same class and two table also has similar locator. So, You need to get the element based on the table name as below

Note: you can achieve this without using JavascriptExecutor

    WebDriverWait wait=new WebDriverWait(driver,20);
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@class='section techD']//span[text()='Technical Details']/ancestor::div[@class='section techD']//table//tr")));

    List<WebElement> rowElementList=driver.findElements(By.xpath("//div[@class='section techD']//span[text()='Technical Details']/ancestor::div[@class='section techD']//table//tr"));
    int row= rowElementList.size();
    System.out.println(row);//16

output: 16

Suppose , If you want to get an additional information table row details, you can use the above Xpath by replace the section as Additional Information

    List<WebElement> additionInfoList=driver.findElements(By.xpath("//div[@class='section techD']//span[text()='Additional Information']/ancestor::div[@class='section techD']//table//tr"));
    System.out.println(additionInfoList.size());//Output: 5

Output: 5

Finally, you can iterate above list and extract table content details

Upvotes: 0

Seetaram Hegde
Seetaram Hegde

Reputation: 41

Instead of absolute xpath:

//*[@id=\"prodDetails\"]/div[2]/div[1]/div/div[2]/div/div/table/tbody/tr  

I would suggest to use simple relative xpath:

//*[@id='prodDetails']//table/tbody/tr  

This xpath will work if there are no other tables in the page. Otherwise, make sure both the tables can be differentiated with some attribute

Upvotes: 0

cruisepandey
cruisepandey

Reputation: 29362

Instead of this xpath :

//*[@id=\"prodDetails\"]/div[2]/div[1]/div/div[2]/div/div/table/tbody/tr  

Use this :

//*[@id="prodDetails"]/div[2]/div[1]/div/div[2]/div/div/table/tbody/tr  

Though I would not suggest you to use absolute xpath. You can go for relative xpath which is more readable and easy.

Relative Xpath :

//div[@id='prodDetails']/descendant::div[@class='pdTab'][1]/descendant::tbody/tr  

In code something like :

List<WebElement>table=driver.findElements(By.xpath("//div[@id='prodDetails']/descendant::div[@class='pdTab'][1]/descendant::tbody/tr"));

Upvotes: 1

Related Questions