为什么 HTML 代码在使用 Jsoup 解析网站时与使用浏览器解析网站时不同
Why HTML code is different when parsing site using Jsoup than using browser
我在网站 http://www.flashscore.com/nhl/ 上,我正在尝试提取“今日比赛”的链接 table。
我用下面的代码试了一下,还是不行,能指出错在哪里吗?
final Document page = Jsoup
.connect("http://d.flashscore.com/x/feed/t_4_200_G2Op923t_1_en_1")
.cookie("_ga","GA1.2.47011772.1485726144")
.referrer("http://d.flashscore.com/x/feed/proxy-local")
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36")
.header("X-Fsign", "SW9D1eZo")
.header("X-GeoIP", "1")
.header("X-Requested-With", "XMLHttpRequest")
.header("Accept" , "*/*")
.get();
for (Element game : page.select("table.hockey tr")) {
Elements links = game.getElementsByClass("tr-first stage-finished");
for (Element link : links) {
String linkHref = link.attr("href");
String linkText = link.text();
}
}
为了尝试修复它,我开始调试它。它表明我们获得了页面(尽管我们得到了一种奇怪的 HTML)。之后调试显示 for 循环甚至没有启动。我试图将 page.select("") 部分更改为不同的部分(如 getElementByAttribute 等),但我刚刚开始学习网络抓取,所以我需要熟悉这些方法来浏览文档.我该如何提取这些数据?
您在 .connect("http://d.flashscore.com/x/feed/t_4_200_G2Op923t_1_en_1")
中获取的地址错误 - 您需要在其中使用 .connect("http://www.flashscore.com/nhl/")
。
然后,此网站使用 JS,在您获得正确的页面后 - 它的呈现方式将不同于浏览器,例如不会有 table 和 class 'hockey'。您会在获得的页面中看到它。
因此,您需要更改定位器。
或者考虑为此使用 WebDriver
。
如评论中所述,该网站需要执行一些 Javascript 才能构建可链接的元素。
Jsoup 仅解析 HTML,它不解析 运行 任何 JS,如果您从浏览器获取或从 Jsoup
获取,您将看不到相同的 HTML 源。
您需要像在真实浏览器上 运行 一样访问该网站。您可以使用 WebDriver
和 Firefox
.
以编程方式执行此操作
我已经尝试使用您的示例网站并有效:
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>
<name>test</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-firefox-driver</artifactId>
<version>2.43.0</version>
</dependency>
</dependencies>
</project>
App.java
package com.test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class App {
public static void main( String[] args ) {
App app = new App();
List<String> links = app.parseLinks();
links.forEach(System.out::println);
}
public List<String> parseLinks() {
try {
WebDriver driver ;
// should download geckodriver https://github.com/mozilla/geckodriver/releases and set according your local file
System.setProperty("webdriver.firefox.marionette","C:\apps\geckodriver.exe");
driver = new FirefoxDriver();
String baseUrl = "http://www.flashscore.com/nhl/";
driver.get(baseUrl);
return driver.findElement(By.className("hockey"))
.findElements(By.tagName("tr"))
.stream()
.distinct()
.filter(we -> !we.getAttribute("id").isEmpty())
.map(we -> createLink(we.getAttribute("id")))
.collect(Collectors.toList());
} catch (Exception e) {
e.printStackTrace();
return Collections.EMPTY_LIST;
}
}
private String createLink(String id) {
return String.format("http://www.flashscore.com/match/%s/#match-summary", extractId(id));
}
private String extractId(String id) {
if (id.contains("x_4_")) {
id = id.replace("x_4_","");
} else if (id.contains("g_4_")) {
id = id.replace("g_4_","");
}
return id;
}
}
输出:
http://www.flashscore.com/match/f9MJJI69/#match-summary
http://www.flashscore.com/match/zZCyd0dC/#match-summary
http://www.flashscore.com/match/drEXdts6/#match-summary
http://www.flashscore.com/match/EJOScMRa/#match-summary
http://www.flashscore.com/match/0GKOb2Cg/#match-summary
http://www.flashscore.com/match/6gLKarcm/#match-summary
...
...
PS:使用 Firefox 版本 32.0 和 Selenium 2.43.0。在 Selenium 和 Firefox 之间使用不受支持的版本是一个常见的错误。
我在网站 http://www.flashscore.com/nhl/ 上,我正在尝试提取“今日比赛”的链接 table。
我用下面的代码试了一下,还是不行,能指出错在哪里吗?
final Document page = Jsoup
.connect("http://d.flashscore.com/x/feed/t_4_200_G2Op923t_1_en_1")
.cookie("_ga","GA1.2.47011772.1485726144")
.referrer("http://d.flashscore.com/x/feed/proxy-local")
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36")
.header("X-Fsign", "SW9D1eZo")
.header("X-GeoIP", "1")
.header("X-Requested-With", "XMLHttpRequest")
.header("Accept" , "*/*")
.get();
for (Element game : page.select("table.hockey tr")) {
Elements links = game.getElementsByClass("tr-first stage-finished");
for (Element link : links) {
String linkHref = link.attr("href");
String linkText = link.text();
}
}
为了尝试修复它,我开始调试它。它表明我们获得了页面(尽管我们得到了一种奇怪的 HTML)。之后调试显示 for 循环甚至没有启动。我试图将 page.select("") 部分更改为不同的部分(如 getElementByAttribute 等),但我刚刚开始学习网络抓取,所以我需要熟悉这些方法来浏览文档.我该如何提取这些数据?
您在 .connect("http://d.flashscore.com/x/feed/t_4_200_G2Op923t_1_en_1")
中获取的地址错误 - 您需要在其中使用 .connect("http://www.flashscore.com/nhl/")
。
然后,此网站使用 JS,在您获得正确的页面后 - 它的呈现方式将不同于浏览器,例如不会有 table 和 class 'hockey'。您会在获得的页面中看到它。
因此,您需要更改定位器。
或者考虑为此使用 WebDriver
。
如评论中所述,该网站需要执行一些 Javascript 才能构建可链接的元素。
Jsoup 仅解析 HTML,它不解析 运行 任何 JS,如果您从浏览器获取或从 Jsoup
获取,您将看不到相同的 HTML 源。
您需要像在真实浏览器上 运行 一样访问该网站。您可以使用 WebDriver
和 Firefox
.
我已经尝试使用您的示例网站并有效:
pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>
<name>test</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-firefox-driver</artifactId>
<version>2.43.0</version>
</dependency>
</dependencies>
</project>
App.java
package com.test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class App {
public static void main( String[] args ) {
App app = new App();
List<String> links = app.parseLinks();
links.forEach(System.out::println);
}
public List<String> parseLinks() {
try {
WebDriver driver ;
// should download geckodriver https://github.com/mozilla/geckodriver/releases and set according your local file
System.setProperty("webdriver.firefox.marionette","C:\apps\geckodriver.exe");
driver = new FirefoxDriver();
String baseUrl = "http://www.flashscore.com/nhl/";
driver.get(baseUrl);
return driver.findElement(By.className("hockey"))
.findElements(By.tagName("tr"))
.stream()
.distinct()
.filter(we -> !we.getAttribute("id").isEmpty())
.map(we -> createLink(we.getAttribute("id")))
.collect(Collectors.toList());
} catch (Exception e) {
e.printStackTrace();
return Collections.EMPTY_LIST;
}
}
private String createLink(String id) {
return String.format("http://www.flashscore.com/match/%s/#match-summary", extractId(id));
}
private String extractId(String id) {
if (id.contains("x_4_")) {
id = id.replace("x_4_","");
} else if (id.contains("g_4_")) {
id = id.replace("g_4_","");
}
return id;
}
}
输出:
http://www.flashscore.com/match/f9MJJI69/#match-summary
http://www.flashscore.com/match/zZCyd0dC/#match-summary
http://www.flashscore.com/match/drEXdts6/#match-summary
http://www.flashscore.com/match/EJOScMRa/#match-summary
http://www.flashscore.com/match/0GKOb2Cg/#match-summary
http://www.flashscore.com/match/6gLKarcm/#match-summary
...
...
PS:使用 Firefox 版本 32.0 和 Selenium 2.43.0。在 Selenium 和 Firefox 之间使用不受支持的版本是一个常见的错误。