1. 概述
Jsoup 是一个开源的Java库,主要用于从HTML中提取数据。它还支持HTML的修改和输出。该库具有稳定的开发路线、完善的文档以及流畅灵活的API。Jsoup同样可用于解析和构建XML。
本教程将以Spring Blog为例,演示一个爬虫练习,展示Jsoup的核心功能:
- 加载:获取HTML并解析为 Document 对象
- 过滤:选择目标数据到 Elements 集合并遍历
- 提取:获取节点的属性、文本和HTML内容
- 修改:添加/编辑/删除节点及其属性
2. Maven依赖
在项目中使用Jsoup,需在 pom.xml 添加依赖:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
最新版本可在Maven中央仓库获取。
3. Jsoup快速入门
Jsoup加载页面HTML并构建对应的DOM树。该树与浏览器中的DOM工作方式相同,提供类似jQuery和原生JavaScript的方法来选择、遍历节点,操作文本/HTML/属性,以及添加/删除元素。
熟悉前端选择器和DOM操作的开发者会很快上手。看这个简单示例——打印页面所有段落:
Document doc = Jsoup.connect("http://example.com").get();
doc.select("p").forEach(System.out::println);
⚠️ 注意:Jsoup只解析HTML,不执行JavaScript。因此浏览器中通过JS动态修改的DOM在Jsoup中不可见。
4. 加载
加载阶段包括获取HTML并解析为 Document。Jsoup能像现代浏览器一样解析任何HTML(无论是否规范)。支持从 String、InputStream、File 或 URL 加载。
从Spring Blog URL加载 Document:
String blogUrl = "https://spring.io/blog";
Document doc = Jsoup.connect(blogUrl).get();
get() 方法表示HTTP GET请求。也可用 post() 或 method() 指定其他HTTP方法。
需处理异常状态码(如404)时,捕获 HttpStatusException:
try {
Document doc404 = Jsoup.connect("https://spring.io/will-not-be-found").get();
} catch (HttpStatusException ex) {
//...
}
有时需要自定义连接。Jsoup.connect(…) 返回的 Connection 对象允许设置:
- User-Agent
- Referrer
- 超时时间
- Cookie
- POST数据
- 请求头
Connection connection = Jsoup.connect(blogUrl);
connection.userAgent("Mozilla");
connection.timeout(5000);
connection.cookie("cookiename", "val234");
connection.referrer("http://google.com");
connection.header("headersecurity", "xyz123");
Document docCustomConn = connection.get();
支持链式调用:
Document docCustomConn = Jsoup.connect(blogUrl)
.userAgent("Mozilla")
.timeout(5000)
.cookie("cookiename", "val234")
.cookie("anothercookie", "ilovejsoup")
.referrer("http://google.com")
.header("headersecurity", "xyz123")
.get();
更多配置参考Connection Javadoc。
5. 过滤
将HTML转换为 Document 后,需导航并定位目标元素。Jsoup的选择器和遍历方法与jQuery/JavaScript高度相似。
5.1. 选择
Document 的 select 方法接收CSS/JavaScript风格的选择器字符串,返回匹配的 Elements 列表(可能为空但非null)。
选择器示例:
Elements links = doc.select("a"); // 所有<a>标签
Elements logo = doc.select(".spring-logo--container"); // class选择器
Elements pagination = doc.select("#pagination_control"); // id选择器
Elements divsDescendant = doc.select("header div"); // 后代选择器
Elements divsDirect = doc.select("header > div"); // 直接子元素
也可使用更明确的DOM方法:
Element pag = doc.getElementById("pagination_control");
Elements desktopOnly = doc.getElementsByClass("desktopOnly");
Element 是 Document 的父类,更多方法见Document和Element文档。
5.2. 遍历
遍历指在DOM树中导航。Jsoup提供在 Document、Elements 集合或单个 Element 上操作的方法,支持访问父节点、兄弟节点或子节点。
常用遍历操作:
Element firstArticle = articles.first(); // 第一个元素
Element lastSection = articles.last(); // 最后一个元素
Element secondSection = articles.get(2); // 第3个元素(0-based)
Elements allParents = firstArticle.parents(); // 所有祖先节点
Element parent = firstArticle.parent(); // 直接父节点
Elements children = firstArticle.children(); // 直接子节点
Elements siblings = firstArticle.siblingElements(); // 兄弟节点
Elements 支持迭代:
articles.forEach(el -> System.out.println("article: " + el));
可在已有选择结果上做子选择:
Elements articleParagraphs = firstArticle.select(".paragraph");
6. 提取
定位元素后,提取其内容——属性、HTML或子文本。
示例:获取博客首篇文章的标题、内部HTML和外部HTML:
Element firstArticle = doc.select("article").first();
Element titleElement= firstArticle.select("h1 a").first();
String titleText= titleElement.text(); // 获取文本
String articleHtml = firstArticle.html(); // 获取内部HTML
String outerHtml = firstArticle.outerHtml(); // 获取包含自身的HTML
选择器使用技巧:
✅ 依赖浏览器"查看源代码"而非DOM(JS可能修改DOM)
✅ 熟悉选择器语法
✅ 使用在线测试工具实验选择器
✅ 优先使用ID等稳定选择器,减少页面变更影响
7. 修改
修改包括设置元素属性/文本/HTML,以及添加/删除元素。操作对象是Jsoup生成的DOM树——Document。
7.1. 设置属性和文本/HTML
类似jQuery,设置方法与获取方法同名但需传入值:
- attr() – 设置属性(不存在则创建)
- text() – 设置元素内部文本(覆盖原内容)
- html() – 设置元素内部HTML(覆盖原内容)
示例:
timeElement.attr("datetime", "2016-12-16 15:19:54.3");
sectionDiv.text("foo bar");
firstArticle.select("h2").html("<div><span></span></div>");
7.2. 创建和添加元素
创建新元素需实例化 Element,然后通过 appendChild 添加到目标元素末尾:
Element link = new Element(Tag.valueOf("a"), "")
.text("Checkout this amazing website!")
.attr("href", "http://baeldung.com")
.attr("target", "_blank");
firstArticle.appendChild(link);
7.3. 删除元素
先选择元素再调用 remove 方法:
doc.select("li.navbar-link").remove(); // 删除所有指定class的<li>
firstArticle.select("img").remove(); // 删除首篇文章所有图片
7.4. 输出修改后的HTML
验证修改结果可通过:
- 重新选择/遍历/提取元素
- 直接输出HTML字符串:
String docHtml = doc.html(); // 获取格式化后的HTML
8. 总结
Jsoup是Java生态中优秀的HTML解析库。若无需浏览器级渲染,它是爬虫任务的首选。其API与前端技术栈高度一致,学习成本低,且遵循良好设计模式。
进一步学习可参考:
本教程源码见GitHub项目。