Selenium webdriver для java API: findElement дает разные результаты

Я использую selenium webdriver для java для обхода этой страницы:

https://www.immowelt.at/liste/wien/wohnungen/mieten?sort=relevanz

В моем коде метод

WebElement.findElement(...)

дает разные результаты, а именно:

1.) Мой исходный код:

package at.home.digest.services;

import java.util.ArrayList;
import java.util.List;


import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import at.home.digest.model.HomeToDeal;

public class ImmoweltBot {

    public static final String URL = "https://www.immowelt.at/";
    public static final String queryURL = URL + "/liste/wien/wohnungen/mieten?sort=relevanz";


    public static void main (String [] args) throws Exception {

        System.setProperty("webdriver.chrome.driver", "C:\\Temp\\chromedriver.exe");

        String URLPage = StringUtils.EMPTY;
        int page = 1;
        int totalNumberOfEntities = 6000;
        int numberOfEntitiesFound = 0;

        List<WebElement> elemnts = new ArrayList<>();

        WebDriver webDriver = new ChromeDriver();

        outer:
        while (numberOfEntitiesFound < totalNumberOfEntities){

        webDriver.get(queryURL + URLPage);


        WebDriverWait wait = new WebDriverWait(webDriver, 5);
        By searchResults = By.xpath("//*[contains(@class, 'clear relative js-listitem')]");

        JavascriptExecutor js = (JavascriptExecutor)webDriver;
        webDriver.manage().window().maximize();
        js.executeScript("window.scrollBy(0,1000)");

        final int totalNumberOfKeyDowns = 190;
        int keyDownTries = 0;
        while ((++keyDownTries < totalNumberOfKeyDowns)) {
            elemnts = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(searchResults));
            webDriver.findElement(By.tagName("body")).sendKeys(Keys.DOWN);

        }

        WebElement elem = webDriver.findElement(By.xpath("//*[contains(@class, 'ellipsis margin_none')]"));
        totalNumberOfEntities = Utils.parseNumber(elem.getText()).intValue();

        for (int i = 0; i < elemnts.size(); i++) {
            WebElement divListItemClear = elemnts.get(i);
            HomeToDeal homeToRent = new HomeToDeal();
            String exposeURL = divListItemClear.findElement(By.tagName("a")).getAttribute("href");
            homeToRent.setURL(exposeURL);

            WebElement listContentClear = divListItemClear.findElement(By.xpath("//*[contains(@class, 'listcontent clear')]"));
            WebElement h2Elem = listContentClear.findElement(By.tagName("h2"));
            String text = h2Elem.getText();
            homeToRent.setDescription(text);

            System.out.println(homeToRent);
        }

        URLPage = "&cp = "+ (++page);
        numberOfEntitiesFound+=elemnts.size();
     }
    }

}

Моя проблема в том, что линия

String exposeURL = divListItemClear.findElement(By.tagName("a")).getAttribute("href");

работает так, как ожидалось, и дает мне последующий URL-адрес элемента (для каждой новой итерации в цикле), однако строки

WebElement listContentClear = divListItemClear.findElement(By.xpath("//*[contains(@class, 'listcontent clear')]"));
        WebElement h2Elem = listContentClear.findElement(By.tagName("h2"));
        String text = h2Elem.getText();

дайте мне КАЖДЫЙ РАЗ ОДНО И ОДИНАКОВОЕ значение HTML-элемента h2-, и это всегда значение первого найденного элемента.

Любые идеи, что я делаю неправильно?

Спасибо!

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы стали жертвой классической ошибки, которую совершают многие люди при использовании XPath с Selenium. Реализации WebDriver следуют спецификации XPath для поиска элементов, что означает, что локатор //всегда относится к верхней части документа. Это даже так, если вы используете findElement из экземпляра WebElement. В коде, на который вы ссылаетесь, который дает ошибку, вы хотите следующее:

WebElement listContentClear = divListItemClear.findElement(By.xpath(".//*[contains(@class, 'listcontent clear')]"));
WebElement h2Elem = listContentClear.findElement(By.tagName("h2"));
String text = h2Elem.getText();

Обратите внимание на . в начале локатора, указывающий текущий узел как узел контекста. Поскольку вы в основном находите элементы на основе значений в классе CSS элементов, это один из случаев, когда использование селекторов CSS вместо XPath позволило бы избежать проблемы.

Кроме того, я бы посчитал эти локаторы несколько хрупкими, поскольку атрибут класса не гарантирует упорядоченность значений класса. Другими словами, с точки зрения браузера <div class = "listcontent clear"> семантически эквивалентен <div class = "clear listcontent">. Если бы браузер отображал элементы как второе, а не как первое, селектор CSS div.listcontent.clear нашел бы оба отображения, а используемый вами XPath — нет.

Другие вопросы по теме