我正在使用 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/