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(无论是否规范)。支持从 StringInputStreamFileURL 加载。

从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. 选择

Documentselect 方法接收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");

ElementDocument 的父类,更多方法见DocumentElement文档。

5.2. 遍历

遍历指在DOM树中导航。Jsoup提供在 DocumentElements 集合或单个 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项目


原始标题:Parsing HTML in Java with Jsoup