简体   繁体   中英

Selenium WebDriver: findElement() in each WebElement from List<WebElement> always returns contents of first element

Page page = new Page();
page.populateProductList( driver.findElement( By.xpath("//div[@id='my_25_products']") ) );

class Page
{
    public final static String ALL_PRODUCTS_PATTERN = "//div[@id='all_products']";

    private List<Product> productList = new ArrayList<>();

    public void populateProductList(final WebElement pProductSectionElement)
    {
        final List<WebElement> productElements = pProductSectionElement.findElements(By.xpath(ALL_PRODUCTS_PATTERN));

        for ( WebElement productElement : productElements ) {
            // test 1 - works 
            // System.out.println( "Product block: " + productElement.getText() );
            final Product product = new Product(productElement);
            // test 2 - wrong
            // System.out.println( "Title: " + product.getUrl() );
            // System.out.println( "Url: " + product.getTitle() );
            productList.add(product);
        }

        // test 3 - works
        //System.out.println(productElements.get(0).findElement(Product.URL_PATTERN).getAttribute("href"));
        //System.out.println(productElements.get(1).findElement(Product.URL_PATTERN).getAttribute("href"));
    }
}

class Product
{
    public final static String URL_PATTERN = "//div[@class='url']/a";
    public final static String TITLE_PATTERN = "//div[@class='title']";

    private String url;
    private String title;

    public Product(final WebElement productElement)
    {
        url = productElement.findElement(By.xpath(URL_PATTERN)).getAttribute("href");
        title = productElement.findElement(By.xpath(TITLE_PATTERN)).getText();
    }

    /* ... */
}

The webpage I am trying to 'parse' with Selenium has a lot of code. I need to deal with just a smaller portion of it that contains the products grid. To the populateProductList() call I pass the resulting portion of the DOM that contains all the products. (Running that XPath in Chrome returns the expected all_products node.)

In that method, I split the products into 25 individual WebElements, ie, the product blocks. (Here I also confirm that works in Chrome and returns the list of nodes, each containing the product data)

Next I want to iterate through the resulting list and pass each WebElement into the Product() constructor that initializes the Product for me. Before I do that I run a small test and print out the product block (see test 1); individual blocks are printed out in each iteraion.

After performing the product assignments (again, xpath confirmed in Chrome) I run another test ( see test 2 ).

Problem: this time the test returns only the url/title pair from the FIRST product for EACH iteration.

Among other things, I tried moving the Product 's findElement() calls into the loop and still had the same problem. Next, I tried running a findElement**s**() and do a get(i).getAttribute("href") on the result; this time it correctly returned individual product URLs (see test 3).

Then when I do a findElements(URL_PATTERN) on a single productElement inside the loop, and it magically returns ALL product urls... This means that findElement() always returns the first product from the set of 25 products, whereas I would expect the WebElement to contain only one product.

I think this looks like a problem with references, but I have not been able to come up with anything or find a solution online.

Any help with this? Thanks!

java 1.7.0_15, Selenium 2.45.0 and FF 37

The problem is in the XPATH of the Product locators.

Below xpath expression in selenium means you are looking for a matching element which in document. 在文档匹配的元素。 Not relative to the parent as you are thinking!!

//div[@class='url']/a

This is why it always returns the same first element.

So, in order to make it relative to the parent element it should be as given below. (just a . before //)

public final static String URL_PATTERN = ".//div[@class='url']/a";
public final static String TITLE_PATTERN = ".//div[@class='title']";

Now you make it search for matching child element relative to the parent.

XPATH in selenium works as given below.

/a/b/c   --> Absolute - from the root

//a/b    --> Matching element which can be anywhere in the document (even outside the parent).

.//a/b   --> Matching element inside the given parent

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM