Jsoup 核心使用方式完整总结
Jsoup 是一款基于 Java 开发的 HTML/XML 解析工具,遵循 WHATWG HTML5 规范,能将各类不规范的 HTML 解析为标准 DOM 树,提供了 DOM 遍历、CSS 选择器、XPath 选择器等便捷的 API,支持从 URL、文件、字符串中解析内容,还能完成 HTML 内容操作、XSS 过滤等功能,是 Java 开发中网页爬虫、HTML 处理的主流工具。
本文结合 Jsoup 官方文档与第三方实战教程,从环境搭建、核心对象获取、元素查找、数据提取、实战案例、高级特性六个维度,详细总结其使用方式。
一、环境搭建
Jsoup 基于 Maven/Gradle 进行依赖管理,也可直接下载 JAR 包引入项目,官方最新版本为 1.21.1,第三方实战常用稳定版 1.12.1。
1. Maven 依赖
<!-- 稳定版 1.12.1 -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
<!-- 官方最新版 1.21.1 -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.21.1</version>
</dependency>
2. Gradle 依赖
implementation 'org.jsoup:jsoup:1.21.1'
二、核心对象:Document 的获取
Jsoup 所有操作均围绕 org.jsoup.nodes.Document 对象展开,该对象代表解析后的 HTML 文档,可从URL、本地文件、字符串三种来源获取,同时支持自定义请求参数模拟浏览器行为。
1. 从 URL 解析(爬虫常用)
通过 Jsoup.connect(String url) 方法创建连接,支持设置请求头、Cookie、超时时间、请求参数等,最终通过 get()/post() 发送请求并解析为 Document。
基础用法
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.IOException;
public class JsoupUrlDemo {
public static void main(String[] args) throws IOException {
// 直接连接 URL 并解析
Document doc = Jsoup.connect("https://www.baidu.com").get();
// 获取网页标题
System.out.println(doc.title());
}
}
自定义请求参数(模拟浏览器)
Document doc = Jsoup.connect("https://example.com")
.data("query", "Java") // 设置请求参数
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/122.0.0.0") // 请求头:浏览器标识
.cookie("auth", "token123") // 设置 Cookie
.timeout(3000) // 超时时间 3 秒
.header("Referer", "https://baidu.com") // 自定义请求头
.post(); // 发送 POST 请求(get() 为 GET 请求)
2. 从本地文件解析
适用于本地 HTML 文件的解析,通过 Jsoup.parse(File file, String charset, String baseUri) 实现,baseUri 用于解析相对路径。
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.File;
import java.io.IOException;
public class JsoupFileDemo {
public static void main(String[] args) throws IOException {
File input = new File("D:/test.html"); // 本地 HTML 文件路径
// 解析文件,编码为 UTF-8,baseUri 为网页根路径
Document doc = Jsoup.parse(input, "UTF-8", "https://example.com");
}
}
3. 从字符串解析
适用于已有 HTML 字符串的场景(如通过 HttpClient 获取的网页源码),直接通过 Jsoup.parse(String html) 解析。
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class JsoupStringDemo {
public static void main(String[] args) {
String html = "<html><head><title>测试页面</title></head><body><p>Hello Jsoup</p></body></html>";
Document doc = Jsoup.parse(html);
System.out.println(doc.title()); // 输出:测试页面
}
}
三、元素查找:从 Document 中获取 Element/Elements
Jsoup 提供DOM 原生方式和CSS 选择器方式两种元素查找方法,其中 CSS 选择器方式功能更强大、语法更简洁,是实际开发的首选;官方还支持 XPath 选择器,进一步提升查找灵活性。
1. DOM 原生方式
通过元素的ID、标签名、类名、属性等原生 DOM 方法查找,方法名语义化,易于理解,适用于简单的元素查找。
| 方法名 | 功能说明 |
|---|---|
getElementById(String id) | 通过 ID 获取单个元素(Element) |
getElementsByTag(String tagName) | 通过标签名获取元素集合(Elements) |
getElementsByClass(String className) | 通过类名获取元素集合(Elements) |
getElementsByAttribute(String key) | 通过属性名获取元素集合(Elements) |
getElementsByAttributeValue(String key, String value) | 通过属性名+属性值获取元素集合(Elements) |
getAllElements() | 获取文档中所有元素(Elements) |
示例
// 通过 ID 获取元素
Element logo = doc.getElementById("logo");
// 通过标签名获取所有 p 标签
Elements pList = doc.getElementsByTag("p");
// 通过类名获取所有 class="content" 的元素
Elements contentList = doc.getElementsByClass("content");
// 通过属性名获取所有带 href 属性的元素
Elements hrefList = doc.getElementsByAttribute("href");
2. CSS 选择器方式(核心)
通过 Element.select(String cssQuery) 方法实现,支持所有 CSS 标准选择器+Jsoup 扩展伪选择器,语法与 jQuery 一致,适用于复杂的元素筛选,是 Jsoup 最核心的功能之一。
2.1 基础选择器(CSS 标准)
涵盖通配符、标签、ID、类、属性等基础筛选规则,可自由组合使用。
| 选择器语法 | 功能说明 | 示例 |
|---|---|---|
* | 匹配所有元素 | doc.select("*") |
tag | 匹配指定标签名的元素 | doc.select("div")(所有 div 标签) |
#id | 匹配指定 ID 的元素 | doc.select("#wrap")(ID 为 wrap 的元素) |
.class | 匹配指定类名的元素 | doc.select(".masthead")(类为 masthead 的元素) |
[attr] | 匹配包含指定属性的元素 | doc.select("[href]")(带 href 属性的元素) |
[attr=val] | 匹配属性值等于 val 的元素 | doc.select("[width=500]") |
[attr^=val] | 匹配属性值以 val 开头的元素 | doc.select("a[href^=http:]")(http 开头的链接) |
[attr$=val] | 匹配属性值以 val 结尾的元素 | doc.select("img[src$=.png]")(png 后缀的图片) |
[attr*=val] | 匹配属性值包含 val的元素 | doc.select("a[href*=/search/]")(包含/search/的链接) |
[attr~=regex] | 匹配属性值符合正则的元素 | `doc.select("img[src~=(?i)\.(png |
el#id/el.class/el[attr] | 元素+ID/类/属性组合 | doc.select("div#logo")(ID 为 logo 的 div) |
2.2 层级关系选择器
用于筛选父子、兄弟、后代关系的元素,精准定位嵌套结构中的目标元素。
| 选择器语法 | 功能说明 | 示例 |
|---|---|---|
ancestor child | 匹配祖先元素下的所有后代子元素 | doc.select(".body p")(.body 下的所有 p 标签) |
parent > child | 匹配父元素的直接子元素(非后代) | doc.select("div.content > p")(div.content 直接子元素 p) |
siblingA + siblingB | 匹配紧接在 siblingA 后的相邻同级元素 | doc.select("li + li")(li 后的下一个 li) |
siblingA ~ siblingX | 匹配 siblingA 后的所有同级元素 | doc.select("h1 ~ p")(h1 后的所有 p 标签) |
el1, el2, el3 | 匹配多个选择器的并集 | doc.select("a[href], div, h3")(带 href 的 a + 所有 div + 所有 h3) |
2.3 Jsoup 扩展伪选择器(重点)
Jsoup 在 CSS 标准基础上扩展了大量伪选择器,用于按索引、文本、子元素等筛选,是复杂筛选的关键,索引从 0 开始。
| 伪选择器语法 | 功能说明 | 示例 |
|---|---|---|
:lt(n) | 匹配同级索引小于 n的元素 | doc.select("td:lt(3)")(前 3 个 td 标签) |
:gt(n) | 匹配同级索引大于 n的元素 | doc.select("div p:gt(2)")(div 下索引>2 的 p 标签) |
:eq(n) | 匹配同级索引等于 n的元素 | doc.select("input:eq(1)")(第二个 input 标签) |
:has(selector) | 匹配包含指定子元素的元素 | doc.select("div:has(p)")(包含 p 标签的 div) |
:not(selector) | 匹配不满足指定选择器的元素 | doc.select("div:not(.logo)")(类不是 logo 的 div) |
:contains(text) | 匹配包含指定文本的元素(忽略大小写,文本可在后代中) | doc.select("p:contains(Jsoup)")(包含 Jsoup 的 p 标签) |
:containsOwn(text) | 匹配直接包含指定文本的元素(文本仅在自身,非后代) | doc.select("p:containsOwn(Java)") |
:matches(regex) | 匹配文本符合正则的元素(忽略大小写,文本可在后代) | doc.select("div:matches((?i)login)")(包含 login 的 div,忽略大小写) |
:empty | 匹配空元素(无子元素/有效文本) | doc.select("li:not(:empty)")(非空的 li 标签) |
:first-child | 匹配父元素的第一个子元素 | doc.select("div > p:first-child") |
:last-child | 匹配父元素的最后一个子元素 | doc.select("ol > li:last-child") |
2.4 官方新增伪选择器(1.21.1+)
官方最新版本新增了更强大的伪选择器,进一步提升筛选能力:
:is(selector list):匹配任意一个选择器的元素,如:is(h1, h2, h3)(所有标题标签);:containsWholeText(text):匹配包含原文本的元素(区分空格/换行,不做文本归一化);:nth-child(an+b):按公式匹配子元素,如tr:nth-child(2n+1)(表格奇数行);:matchText:将文本节点视为元素,支持匹配文本节点,如p:matchText:firstChild。
CSS 选择器综合示例
// 选择所有带 href 属性的 a 标签
Elements links = doc.select("a[href]");
// 选择 class 为 masthead 的第一个 div 标签
Element masthead = doc.select("div.masthead").first();
// 选择 h3 标签内的直接子元素 a 标签
Elements resultLinks = doc.select("h3 > a");
// 选择包含“2020年高职扩招”的 td 下的 a 标签(实战常用)
Elements schoolLinks = doc.select("td a[href]:contains(2020年高职扩招)");
3. XPath 选择器
Jsoup 官方支持 XPath 语法查找元素,需结合 XPathEvaluator 使用,适用于习惯 XPath 的开发者,可实现更灵活的节点遍历。
示例
import org.jsoup.nodes.Document;
import org.jsoup.select.XPathEvaluator;
import org.jsoup.select.XPathResult;
public class JsoupXPathDemo {
public static void main(String[] args) throws Exception {
Document doc = Jsoup.connect("https://example.com").get();
// 定义 XPath 表达式:选择所有 div 下的 p 标签
XPathEvaluator evaluator = XPathEvaluator.compile("//div/p");
XPathResult result = evaluator.evaluate(doc);
// 遍历结果
result.forEach(element -> System.out.println(element.text()));
}
}
四、数据提取:从 Element/Elements 中获取内容
找到目标元素后,通过 Jsoup 提供的 API 提取文本、HTML 内容、属性值、URL等核心数据,Elements 是 Element 的集合,可通过遍历获取单个 Element 后再提取数据。
1. 文本提取
| 方法 | 功能说明 |
|---|---|
Element.text() | 获取元素的纯文本内容(去除所有 HTML 标签,合并后代文本) |
Element.ownText() | 获取元素自身的纯文本(不包含后代元素的文本) |
示例
// 获取元素所有纯文本
String text = element.text();
// 获取元素自身纯文本
String ownText = element.ownText();
2. HTML 内容提取
| 方法 | 功能说明 |
|---|---|
Element.html() | 获取元素内部的 HTML 内容(包含子元素标签) |
Node.outerHtml() | 获取元素自身+内部的全部 HTML 内容(包含当前元素标签) |
Document.html() | 获取整个文档的 HTML 内容 |
示例
// 内部 HTML(子元素)
String innerHtml = element.html();
// 全部 HTML(自身+子元素)
String outerHtml = element.outerHtml();
3. 属性值提取
核心方法:Element.attr(String key),传入属性名即可获取属性值,支持所有 HTML 原生属性(href、src、class、id 等),是爬虫提取链接、图片地址的核心方法。
示例
// 提取 a 标签的链接(href)
String href = element.attr("href");
// 提取 img 标签的图片地址(src)
String src = element.attr("src");
// 提取元素的类名(class)
String className = element.attr("class");
4. URL 标准化提取
针对链接(href)、图片地址(src)等相对路径,Jsoup 提供了绝对路径转换方法,避免路径失效。
// 提取绝对路径的链接(自动拼接 baseUri)
String absHref = element.absUrl("href");
// 提取绝对路径的图片地址
String absSrc = element.absUrl("src");
5. 集合遍历提取
Elements 是元素集合,需通过增强 for 循环或流式遍历提取每个元素的内容:
Elements links = doc.select("a[href]");
// 增强 for 循环
for (Element link : links) {
String text = link.text(); // 链接文本
String href = link.absUrl("href"); // 绝对链接
System.out.println(text + " : " + href);
}
// 流式遍历(Java 8+)
links.stream().forEach(link -> {
System.out.println(link.text() + " : " + link.absUrl("href"));
});
五、实战案例:网页数据爬取(高职扩招信息抓取)
结合上述所有知识点,实现多页网页爬取:抓取教育网站上 2020 年高职扩招的学校名称及对应链接,覆盖URL 拼接、CSS 选择器筛选、元素遍历、数据提取核心步骤。
完整代码
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
/**
* Jsoup 实战:抓取2020年高职扩招学校名称及链接
*/
@Slf4j
public class JsoupCrawlDemo {
public static void main(String[] args) throws IOException {
// 目标URL(分页参数为?page=1、?page=2...)
String baseUrl = "http://xxx/result/query";
// 爬取第1-5页
for (int i = 1; i < 6; i++) {
String url = baseUrl + "?page=" + i;
// 1. 连接URL并解析为Document
Document doc = Jsoup.connect(url).timeout(5000).get();
log.info("开始爬取第{}页,URL:{}", i, url);
// 2. CSS选择器筛选目标元素:td下带href、包含指定文本的a标签
Elements schoolLinks1 = doc.select("td a[href]:contains(2020年高职扩招)");
Elements schoolLinks2 = doc.select("td a[href]:contains(2020年扩招)");
// 合并两个结果集,避免遗漏
schoolLinks1.addAll(schoolLinks2);
log.info("第{}页找到{}所学校", i, schoolLinks1.size());
// 3. 遍历元素,提取数据
if (!schoolLinks1.isEmpty()) {
for (Element link : schoolLinks1) {
String schoolName = link.text(); // 学校名称
String schoolHref = link.absUrl("href"); // 学校链接(绝对路径)
log.info("学校名称:{},链接:{}", schoolName, schoolHref);
}
}
}
}
}
核心要点
- 分页处理:通过拼接
?page=i实现多页爬取; - 精准筛选:使用
:contains伪选择器筛选包含指定文本的元素,避免无效数据; - 结果合并:将两个相似条件的结果集合并,防止数据遗漏;
- 绝对路径:使用
absUrl()提取链接,避免相对路径导致的访问失败; - 超时设置:通过
timeout(5000)设置超时,防止请求阻塞。
六、Jsoup 高级特性
1. 模拟登录与 Cookie 管理
爬取需要登录的网页时,通过 Jsoup 的 Connection 对象执行登录请求,获取返回的 Cookie,后续请求携带该 Cookie 即可实现登录态保持。
import org.jsoup.Jsoup;
import org.jsoup.Connection;
import org.jsoup.Connection.Response;
import java.io.IOException;
import java.util.Map;
public class JsoupLoginDemo {
public static void main(String[] args) throws IOException {
// 登录接口URL
String loginUrl = "http://www.iotcloud168.com:8083/user/login?username=181228001&password=123";
// 执行登录请求
Connection connect = Jsoup.connect(loginUrl);
Response response = connect.execute();
// 获取登录后的Cookie
Map<String, String> cookies = response.cookies();
// 后续请求携带Cookie,实现登录态
Document doc = Jsoup.connect("http://www.iotcloud168.com:8083/user/info")
.cookies(cookies) // 携带登录Cookie
.get();
}
}
2. HTML 内容操作
Jsoup 支持对 HTML 元素进行新增、修改、删除操作,适用于 HTML 文档处理。
// 修改元素文本
element.text("新的文本内容");
// 修改元素HTML
element.html("<p>新的HTML内容</p>");
// 修改元素属性
element.attr("href", "https://new-url.com");
// 新增子元素
element.append("<span>新增子元素</span>");
// 删除元素
element.remove();
3. XSS 过滤(HTML 清洗)
Jsoup 提供内置的 XSS 过滤工具,可通过白名单过滤不安全的 HTML 标签和属性,防止用户提交的内容包含 XSS 攻击代码。
import org.jsoup.Jsoup;
import org.jsoup.safety.Safelist;
public class JsoupXssDemo {
public static void main(String[] args) {
// 待清洗的HTML(包含恶意脚本)
String unsafeHtml = "<p>测试</p><script>alert('XSS')</script><img src=x onerror=alert(1)>";
// 使用官方默认白名单(仅允许基本的文本标签)
Safelist safelist = Safelist.basic();
// 清洗HTML,过滤恶意代码
String safeHtml = Jsoup.clean(unsafeHtml, safelist);
System.out.println(safeHtml); // 输出:<p>测试</p><img>
}
}
Jsoup 提供多种预设白名单,可根据需求选择:Safelist.none()(无标签)、Safelist.simpleText()(仅文本)、Safelist.basic()(基本文本标签)、Safelist.relaxed()(宽松模式,允许大部分标签)。
4. 大文档高效解析
针对超大 HTML 文档,Jsoup 提供 StreamParser 实现流式解析,避免一次性加载整个文档到内存,提升解析效率。
import org.jsoup.parser.StreamParser;
import java.io.FileReader;
import java.io.Reader;
public class JsoupStreamDemo {
public static void main(String[] args) throws Exception {
Reader reader = new FileReader("D:/large.html");
// 流式解析,逐行处理
StreamParser parser = new StreamParser(reader);
parser.parse((event, position) -> {
// 处理解析事件(如标签开始、文本节点等)
System.out.println(event);
return true; // 继续解析
});
}
}
七、核心总结
- 核心定位:Jsoup 是 Java 生态最优秀的 HTML 解析工具,主打便捷性和兼容性,能处理各类不规范的 HTML;
- 核心流程:
获取Document→查找Element/Elements→提取数据,是爬虫开发的固定流程; - 核心技能:CSS 选择器是 Jsoup 的核心,掌握基础选择器+层级选择器+扩展伪选择器,就能解决 99% 的元素查找问题;
- 实战技巧:提取链接时优先使用
absUrl()转换为绝对路径,爬取多页时做好超时设置,登录场景需管理 Cookie; - 高级能力:除了爬虫,Jsoup 还能实现 HTML 内容操作、XSS 过滤、大文档流式解析,是前端/后端 HTML 处理的通用工具。
Jsoup 遵循 MIT 开源协议,源码托管在 GitHub,官方文档提供了丰富的示例和 Cookbook,是学习和使用的最佳参考。
https://jsoup.org/
https://jsoup.org/apidocs/org/jsoup/select/Selector.html
https://tio-boot.litongjava.com/zh/34_spider/01.html