java - 用于java API的selenium webdriver : findElement produces different results

标签 java selenium selenium-webdriver selenium-chromedriver

我正在使用 java 的 selenium webdriver 来抓取此页面:

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- 值,这始终是找到的第一个元素的值。

有什么想法我做错了什么吗?

谢谢!

最佳答案

您已经成为许多人在将 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 则不会。

关于java - 用于java API的selenium webdriver : findElement produces different results,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56715832/

相关文章:

java - Jenkins 无法在 Tomcat 9 上运行

Java class.getResource() 返回 null

java - 在 java 中将 hashmap<String,String[]> 的值写入为 csv 文件

java - 使用 Selenium Java 在网页上按多个选项卡

java - 无法单击 TreeView 中的元素 - Selenium webdriver java

java - 使用 WebDriver 暂时绕过隐式等待

java - 根据最长长度的数字打印出特定数量的数字?

javascript - 如何在 contenteditable span 中设置插入符号位置然后发送 key ?

selenium - 在 chromedriver (Selenium) 中导入根 CA

c# - 使用 Selenium WebDriver C# 最大化 Firefox 的浏览器窗口