在本指南中,我们将介绍以下内容:
- 什么是 Jsoup?
- 先决条件
- 如何使用 Jsoup 构建网页抓取工具
- 结论
什么是 Jsoup?
Jsoup 是一个 Java HTML 解析器。换句话说,Jsoup 是一个允许你解析任何 HTML 文档的 Java 库。使用 Jsoup,你可以解析本地 HTML 文件,或从 URL 下载远程 HTML 文档。
Jsoup 还提供了广泛的方法来处理 DOM。具体来说,你可以使用 CSS 选择器和类似 Jquery 的方法来选择 HTML 元素并从中提取数据。这使 Jsoup 成为适合初学者和专业人士的有效网页抓取 Java 库。
请注意,Jsoup 并不是在 Java 中执行网页抓取的唯一库。HtmlUnit 是另一个流行的网页抓取 Java 库。请查看我们的 Java 中使用 HtmlUnit 进行网页抓取指南。
先决条件
在编写第一行代码之前,你必须满足以下先决条件:
- Java >= 8:任何大于或等于 8 的 Java 版本都可以。建议下载并安装 Java 的 LTS(长期支持)版本。具体来说,本教程基于 Java 17。在撰写本文时,Java 17 是 Java 的最新 LTS 版本。
- Maven 或 Gradle:你可以选择任何你偏好的 Java 构建自动化工具。具体来说,你需要 Maven 或 Gradle 来使用它们的依赖管理功能。
- 支持 Java 的高级 IDE:任何支持带有 Maven 或 Gradle 的 Java 的 IDE 都可以。本教程基于 IntelliJ IDEA,它可能是目前最好的 Java IDE。
按照上面的链接下载并安装满足所有先决条件所需的一切。按顺序设置 Java、Maven 或 Gradle,以及用于 Java 的 IDE。按照官方安装指南操作,以避免常见问题和故障。
现在让我们验证你是否满足所有先决条件。
验证 Java 是否正确配置
打开你的终端。你可以使用下面的命令验证你是否安装了 Java 并正确设置了 Java PATH:
java -version
此命令应打印类似如下的内容:
java version "17.0.5" 2022-10-18 LTS
Java(TM) SE Runtime Environment (build 17.0.5+9-LTS-191)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.5+9-LTS-191, mixed mode, sharing)
验证 Maven 或 Gradle 是否已安装
如果你选择了 Maven,请在终端中运行以下命令:
mvn -v
你应该会获得一些关于你配置的 Maven 版本的信息,如下所示:
Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63)
Maven home: C:Mavenapache-maven-3.8.6
Java version: 17.0.5, vendor: Oracle Corporation, runtime: C:Program FilesJavajdk-17.0.5
Default locale: en_US, platform encoding: Cp1252
OS name: "windows 11", version: "10.0", arch: "amd64", family: "windows"
而如果你选择了 Gradle,请在终端中执行:
gradle -v
同样,这应该会打印一些关于你安装的 Gradle 版本的信息,如下所示:
------------------------------------------------------------
Gradle 7.5.1
------------------------------------------------------------
Build time: 2022-08-05 21:17:56 UTC
Revision: d1daa0cbf1a0103000b71484e1dbfe096e095918
Kotlin: 1.6.21
Groovy: 3.0.10
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 17.0.5 (Oracle Corporation 17.0.5+9-LTS-191)
OS: Windows 11 10.0 amd64
太好了!你现在已经准备好学习如何在 Java 中使用 Jsoup 执行网页抓取了!
如何使用 Jsoup 构建网页抓取工具
在这里,你将学习如何使用 Jsoup 构建一个用于网页抓取的脚本。该脚本将能够自动从网站提取数据。具体来说,目标网站是 Quotes to Scrape。如果你不熟悉这个项目,它不过是一个用于网页抓取的沙盒。
Quotes to Scrape 看起来是这样的:

Quotes to Scrape 概览
如你所见,目标网站只包含一个分页的引语列表。Jsoup 网页爬虫工具的目标是遍历每个页面,检索所有引语,并以 CSV 格式返回这些数据。
现在,按照这个逐步的 Jsoup 教程,学习如何构建一个简单的爬虫工具!
第 1 步:设置 Java 项目
在这里,你将看到如何在 IntelliJ IDEA 2022.2.3 中初始化 Java 项目。请注意,任何其他 IDE 都可以。在 IntelliJ IDEA 中,只需点击几下即可设置 Java 项目。启动 IntelliJ IDEA 并等待它加载。然后,在顶部菜单中选择 File > New > Project... 选项。

IntelliJ IDEA 中的 File > New > Project… 选项
现在,在 New Project 弹窗中按如下方式初始化你的 Java 项目:

在 IltelliJ IDEA 中设置 Java 项目
为你的项目指定名称和位置,选择 Java 作为编程语言,并根据你安装的构建工具在 Maven 或 Gradle 之间进行选择。点击 Create 按钮并等待 IntelliJ IDEA 初始化你的 Java 项目。你现在应该会看到以下空的 Java 项目:

IltelliJ IDEA 自动创建 Main.java 类
现在是安装 Jsoup 并开始从 Web 抓取数据的时候了!
第 2 步:安装 Jsoup
如果你是 Maven 用户,请将下面的行添加到你的 pom.xml 文件的 dependencies 标签内:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
</dependency>
你的 Maven pom.xml 文件现在应该如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.brightdata</groupId>
<artifactId>web-scraper-jsoup</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
</dependency>
</dependencies>
</project>
或者,如果你是 Gradle 用户,请将这一行添加到你的 build.gradle 文件的 dependencies 对象中:
implementation "org.jsoup:jsoup:1.15.3"
你刚刚将 jsoup 添加到了项目的依赖项中。现在是安装它的时候了。在 IntelliJ IDEA 中,点击下面的 Gradle/Maven 重新加载按钮:

Maven 重新加载按钮
这将安装 jsoup 依赖项。等待安装过程结束。你现在可以访问所有 Jsoup 功能。你可以通过在 Main.java 文件顶部添加此 import 行来验证 Jsoup 是否正确安装:
import org.jsoup.*;
如果 IntelliJ IDEA 没有报告错误,这意味着你现在可以在你的 Java 网页抓取脚本中使用 Jsoup。
现在让我们用 Jsoup 编写一个网页爬虫工具!
第 3 步:连接到你的目标网页
你可以使用 Jsoup 通过一行代码连接到目标网站:
// downloading the target website with an HTTP GET request
Document doc = Jsoup.connect("https://quotes.toscrape.com/").get();
借助 Jsoup 的 connect() 方法,你可以连接到一个网站。其背后的过程是:Jsoup 会向作为参数指定的 URL 发起 HTTP GET 请求,获取目标服务器返回的 HTML 文档,并将其存储在 doc 这个 Jsoup Document 对象中。
请记住,如果 connect() 失败,Jsoup 会抛出 IOException。这可能由多种原因导致。不过,你需要注意,许多网站会拦截不包含有效 User-Agent 请求头的请求。如果你不熟悉这一点,User-Agent 请求头是一个字符串值,用于标识发起请求的应用程序和操作系统版本。进一步了解用于网页抓取的 User-Agent。
你可以在 Jsoup 中按如下方式指定 User-Agent 请求头:
Document doc = Jsoup
.connect("https://quotes.toscrape.com/")
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36")
.get();
具体来说,Jsoup 的 userAgent() 方法允许你设置 User-Agent 请求头。请注意,你也可以通过 header() 方法为任何其他 HTTP 请求头设置值。
你的 Main.java 类现在应如下所示:
package com.brightdata;
import org.jsoup.*;
import org.jsoup.nodes.*;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
// downloading the target website with an HTTP GET request
Document doc = Jsoup
.connect("https://quotes.toscrape.com/")
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36")
.get();
}
}
让我们开始分析目标网站,学习如何从中提取数据。
第 4 步:检查 HTML 页面
如果你想从 HTML 文档中提取数据,必须先分析网页的 HTML 代码。首先,你必须识别包含你想抓取的数据的 HTML 元素。然后,你必须找到一种选择这些 HTML 元素的方法。
你可以通过浏览器的开发者工具完成所有这些操作。在 Google Chrome 或任何基于 Chromium 的浏览器中,右键单击显示某些感兴趣数据的 HTML 元素。然后,选择 Inspect。

在第一个引语 HTML 元素上选择 Inspect 选项
这是你现在应该看到的内容:

在 Chrome DevTools 中检查引语 HTML 元素
通过深入查看 HTML 代码,你可以看到每条名言都被包裹在一个 <div> HTML 元素中。具体来说,这个 <div> 元素包含:
- 一个包含名言文本的
<span>HTML 元素 - 一个包含作者姓名的
<small>HTML 元素 - 一个
<div>元素,其中包含一组<a>HTML 元素,这些元素包含与该名言相关的标签。
现在,看一下这些 HTML 元素使用的 CSS 类。借助这些类,你可以定义所需的 CSS 选择器,从 DOM 中提取这些 HTML 元素。具体来说,你可以通过在下面的 .quote 上应用 CSS 选择器,检索与某条名言相关的所有数据:
.text.author.tags .tag
现在,让我们学习如何在 Jsoup 中实现这一点。
第 5 步:使用 Jsoup 选择 HTML 元素
Jsoup 的 Document 类提供了多种从 DOM 中选择 HTML 元素的方法。让我们深入了解其中最重要的几种。
Jsoup 允许你根据标签提取 HTML 元素:
// selecting all <div> HTML elements
Elements divs = doc.getElementsByTag("div");
这将返回 DOM 中包含的 <div> HTML 元素列表。
类似地,你可以按 class 选择 HTML 元素:
// getting the ".quote" HTML element
Elements quotes = doc.getElementsByClass("quote");
如果你想根据某个 HTML 元素的 id 属性检索单个 HTML 元素,可以使用:
// getting the "#quote-1" HTML element
Element div = doc.getElementById("quote-1");
你也可以按属性选择 HTML 元素:
// selecting all HTML elements that have the "value" attribute
Elements htmlElements = doc.getElementsByAttribute("value");
或者选择包含特定文本片段的元素:
// selecting all HTML elements that contain the word "for"
Elements htmlElements = doc.getElementsContainingText("for");
这些只是几个示例。请记住,Jsoup 提供了 20 多种从网页中选择 HTML 元素的方法。查看全部方法。
如前所述,CSS 选择器是选择 HTML 元素的一种有效方式。你可以通过 select() 方法,在 Jsoup 中应用 CSS 选择器来检索元素:
// selecting all quote HTML elements
Elements quoteElements = doc.getElementsByClass(".quote");
由于 Elements 继承自 ArrayList,因此你可以对其进行迭代,以获取每一个 Jsoup Element。请注意,你也可以将所有 HTML 选择方法应用于单个 Element。这样会将选择逻辑限制在所选 HTML 元素的子元素范围内。
因此,你可以按如下方式在每个 .quote 中选择所需的 HTML 元素:
for (Element quoteElement: quoteElements) {
Element text = quoteElement.select(".text").first();
Element author = quoteElement.select(".author").first();
Elements tags = quoteElement.select(".tag");
}
现在,让我们学习如何从这些 HTML 元素中提取数据。
第 6 步:使用 Jsoup 从网页中提取数据
首先,你需要一个 Java 类来存储抓取到的数据。在主包中创建一个 Quote.java 文件,并按如下方式初始化:
package com.brightdata;
package com.brightdata;
public class Quote {
private String text;
private String author;
private String tags;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTags() {
return tags;
}
public void setTags(String tags) {
this.tags = tags;
}
}
现在,让我们扩展上一节末尾展示的代码片段。从选中的 HTML 元素中提取所需数据,并按如下方式将其存储到 Quote 对象中:
// initializing the list of Quote data objects
// that will contain the scraped data
List<Quote> quotes = new ArrayList<>();
// retrieving the list of product HTML elements
// selecting all quote HTML elements
Elements quoteElements = doc.select(".quote");
// iterating over the quoteElements list of HTML quotes
for (Element quoteElement : quoteElements) {
// initializing a quote data object
Quote quote = new Quote();
// extracting the text of the quote and removing the
// special characters
String text = quoteElement.select(".text").first().text()
.replace("“", "")
.replace("”", "");
String author = quoteElement.select(".author").first().text();
// initializing the list of tags
List<String> tags = new ArrayList<>();
// iterating over the list of tags
for (Element tag : quoteElement.select(".tag")) {
// adding the tag string to the list of tags
tags.add(tag.text());
}
// storing the scraped data in the Quote object
quote.setText(text);
quote.setAuthor(author);
quote.setTags(String.join(", ", tags)); // merging the tags into a "A, B, ..., Z" string
// adding the Quote object to the list of the scraped quotes
quotes.add(quote);
}
由于每条名言可能有多个标签,你可以将它们全部存储在 Java 的 List 中。然后,你可以使用 String.join() 方法,将字符串列表合并为单个字符串。最后,你可以将这个字符串存储到 quote 对象中。
在 for 循环结束时,quotes 将存储从目标网站首页提取出的所有名言数据。但目标网站包含很多页面!
让我们学习如何使用 Jsoup 爬取整个网站。
第 7 步:如何使用 Jsoup 爬取整个网站
如果你仔细查看 Quotes to Scrape 首页,会注意到一个“Next →”按钮。使用浏览器的开发者工具检查这个 HTML 元素。右键点击它,然后选择 Inspect。

检查 “Next →” 按钮
在这里,你可以注意到 “Next →” 按钮是 <li> HTML 元素。它包含一个 <a> HTML 元素,该元素存储指向下一页的相对 URL。请注意,除了目标网站的最后一页之外,你可以在所有页面上找到 “Next →” 按钮。大多数分页网站都遵循这种方法。
通过提取存储在该 <a> HTML 元素中的链接,你可以获取要抓取的下一页。因此,如果你想抓取整个网站,请遵循以下逻辑:
- 搜索
.nextHTML 元素- 如果存在,提取其
<a>子元素中包含的相对 URL,并转到 2。 - 如果不存在,这就是最后一页,你可以在此停止
- 如果存在,提取其
- 将
<a>HTML 元素提取的相对 URL 与网站的基础 URL 拼接 - 使用完整 URL 连接到新页面
- 从新页面抓取数据
- 转到 1。
这就是网页爬取的含义。你可以使用 Jsoup 如下爬取分页网站:
// the URL of the target website's home page
String baseUrl = "https://quotes.toscrape.com";
// initializing the list of Quote data objects
// that will contain the scraped data
List<Quote> quotes = new ArrayList<>();
// retrieving the home page...
// looking for the "Next →" HTML element
Elements nextElements = doc.select(".next");
// if there is a next page to scrape
while (!nextElements.isEmpty()) {
// getting the "Next →" HTML element
Element nextElement = nextElements.first();
// extracting the relative URL of the next page
String relativeUrl = nextElement.getElementsByTag("a").first().attr("href");
// building the complete URL of the next page
String completeUrl = baseUrl + relativeUrl;
// connecting to the next page
doc = Jsoup
.connect(completeUrl)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36")
.get();
// scraping logic...
// looking for the "Next →" HTML element in the new page
nextElements = doc.select(".next");
}
正如你所看到的,你可以使用一个简单的 while 循环来实现上面解释的爬取逻辑。只需要几行代码即可。具体来说,你需要采用 do ... while 方式。
恭喜!你现在已经能够爬取整个网站。剩下的就是学习如何将抓取到的数据转换为更实用的格式。
第 8 步:将抓取的数据导出为 CSV
你可以按如下方式将抓取的数据转换为 CSV 文件:
// initializing the output CSV file
File csvFile = new File("output.csv");
// using the try-with-resources to handle the
// release of the unused resources when the writing process ends
try (PrintWriter printWriter = new PrintWriter(csvFile)) {
// iterating over all quotes
for (Quote quote : quotes) {
// converting the quote data into a
// list of strings
List<String> row = new ArrayList<>();
// wrapping each field with between quotes
// to make the CSV file more consistent
row.add(""" + quote.getText() + """);
row.add(""" +quote.getAuthor() + """);
row.add(""" +quote.getTags() + """);
// printing a CSV line
printWriter.println(String.join(",", row));
}
}
这段代码会将名言转换为 CSV 格式,并将其存储在 output.csv 文件中。正如你所看到的,实现这一点并不需要额外的依赖。你只需要使用 File 初始化一个 CSV 文件。然后,可以通过 PrintWriter 将每个 quote 以 CSV 格式的行写入 output.csv 文件。
请注意,当你不再需要 PrintWriter 时,应始终将其关闭。具体来说,上面的 try-with-resources 会确保 PrintWriter 实例在 try 语句结束时被关闭。
你从浏览网站开始,现在已经可以抓取其所有数据并将其存储到 CSV 文件中。现在,是时候看看完整的 Jsoup 网页爬虫工具了。
整合全部内容
这是完整的 Java 中 Jsoup 网页抓取脚本的样子:
package com.brightdata;
import org.jsoup.*;
import org.jsoup.nodes.*;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) throws IOException {
// the URL of the target website's home page
String baseUrl = "https://quotes.toscrape.com";
// initializing the list of Quote data objects
// that will contain the scraped data
List<Quote> quotes = new ArrayList<>();
// downloading the target website with an HTTP GET request
Document doc = Jsoup
.connect(baseUrl)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36")
.get();
// looking for the "Next →" HTML element
Elements nextElements = doc.select(".next");
// if there is a next page to scrape
while (!nextElements.isEmpty()) {
// getting the "Next →" HTML element
Element nextElement = nextElements.first();
// extracting the relative URL of the next page
String relativeUrl = nextElement.getElementsByTag("a").first().attr("href");
// building the complete URL of the next page
String completeUrl = baseUrl + relativeUrl;
// connecting to the next page
doc = Jsoup
.connect(completeUrl)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36")
.get();
// retrieving the list of product HTML elements
// selecting all quote HTML elements
Elements quoteElements = doc.select(".quote");
// iterating over the quoteElements list of HTML quotes
for (Element quoteElement : quoteElements) {
// initializing a quote data object
Quote quote = new Quote();
// extracting the text of the quote and removing the
// special characters
String text = quoteElement.select(".text").first().text();
String author = quoteElement.select(".author").first().text();
// initializing the list of tags
List<String> tags = new ArrayList<>();
// iterating over the list of tags
for (Element tag : quoteElement.select(".tag")) {
// adding the tag string to the list of tags
tags.add(tag.text());
}
// storing the scraped data in the Quote object
quote.setText(text);
quote.setAuthor(author);
quote.setTags(String.join(", ", tags)); // merging the tags into a "A; B; ...; Z" string
// adding the Quote object to the list of the scraped quotes
quotes.add(quote);
}
// looking for the "Next →" HTML element in the new page
nextElements = doc.select(".next");
}
// initializing the output CSV file
File csvFile = new File("output.csv");
// using the try-with-resources to handle the
// release of the unused resources when the writing process ends
try (PrintWriter printWriter = new PrintWriter(csvFile, StandardCharsets.UTF_8)) {
// to handle BOM
printWriter.write('ufeff');
// iterating over all quotes
for (Quote quote : quotes) {
// converting the quote data into a
// list of strings
List<String> row = new ArrayList<>();
// wrapping each field with between quotes
// to make the CSV file more consistent
row.add(""" + quote.getText() + """);
row.add(""" +quote.getAuthor() + """);
row.add(""" +quote.getTags() + """);
// printing a CSV line
printWriter.println(String.join(",", row));
}
}
}
}
如这里所示,你可以用不到 100 行代码在 Java 中实现一个网页爬虫工具。借助 Jsoup,你可以连接到网站,完整爬取它,并自动提取其所有数据。然后,你可以将抓取的数据写入 CSV 文件。这就是这个 Jsoup 网页抓取工具的作用。
在 IntelliJ IDEA 中,通过点击下面的按钮启动网页抓取 Jsoup 脚本:

在 IntelliJ IDEA 中启动 Java 脚本
IntelliJ IDEA 将编译 Main.java 文件并执行 Main 类。在抓取过程结束时,你将在项目的根目录中找到一个 output.csv 文件。打开它,它应该包含这些数据:

output.csv 文件
做得好!你现在有一个包含 Quotes to Scrape 全部 100 条引语的 CSV 文件!这意味着你刚刚学会了如何使用 Jsoup 构建一个网页抓取工具!
结论
在本教程中,你学习了开始构建网页爬虫工具所需的内容、Jsoup 是什么,以及如何使用它从 Web 抓取数据。具体来说,你通过一个真实示例了解了如何使用 Jsoup 构建网页抓取应用程序。正如你所学到的,在 Java 中使用 Jsoup 进行网页抓取只涉及少量代码行。
然而,网页抓取并没有那么容易。这是因为你必须面对若干挑战。不要忘记,反机器人和反抓取技术现在比以往任何时候都更流行。你所需要的是一个强大且功能齐全的网页抓取工具,由 Bright Data 提供。完全不想处理抓取?看看我们的数据集。
如果你想了解更多关于如何避免被封锁的信息,可以根据你的使用场景,从 Bright Data 中众多可用的代理服务中采用一种代理。联系我们,为你的项目找到完美的解决方案。