ZetCode

Java JSoup

上次修改时间:2024 年 7 月 4 日

JSoup 教程是一个 JSoup HTML 解析器的入门指南。在本教程中,我们将从 HTML 字符串、本地 HTML 文件和网页中解析 HTML 数据。我们将对数据进行清理并执行 Google 搜索。

JSoup 是一个用于提取和操作 HTML 数据的 Java 库。 它实现了 HTML5 规范,并将 HTML 解析为与现代浏览器相同的 DOM。

使用 JSoup,我们可以

依赖

在本教程的示例中,我们使用以下 Maven 依赖项。

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.17.2</version>
</dependency>

JSoup 类通过其静态方法提供对 jsoup 功能的核心公共访问点。 例如,clean 方法清理 HTML 代码,connect 方法创建到 URL 的连接,或者 parse 方法解析 HTML 内容。

HTML 文件

在某些示例中,我们使用以下 HTML 文件

words.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document title</title>
</head>
<body>
<p>List of words</p>
<ul>
    <li>dark</li>
    <li>smart</li>
    <li>war</li>
    <li>cloud</li>
    <li>park</li>
    <li>cup</li>
    <li>worm</li>
    <li>water</li>
    <li>rock</li>
    <li>warm</li>
</ul>
<footer>footer for words</footer>
</body>
</html>

解析 HTML 字符串

JSoup.parse 方法将 HTML 字符串解析为文档。

Main.java
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

void main() {

    String htmlString = """
            <html><head><title>My title</title></head>
            <body>Body content</body></html>""";

    Document doc = Jsoup.parse(htmlString);
    String title = doc.title();
    String body = doc.body().text();

    System.out.printf("Title: %s%n", title);
    System.out.printf("Body: %s", body);
}

该示例解析 HTML 字符串并输出其标题和正文内容。

String htmlString = """
    <html><head><title>My title</title></head>
    <body>Body content</body></html>""";

此字符串包含简单的 HTML 数据。

Document doc = Jsoup.parse(htmlString);

使用 Jsoup 的 parse 方法,我们解析 HTML 字符串。该方法返回一个 HTML 文档。

String title = doc.title();

文档的 title 方法获取文档标题元素的字符串内容。

String body = doc.body().text();

文档的 body 方法返回正文元素;它的 text 方法获取元素的文本。

JSoup 解析本地 HTML 文件

在第二个示例中,我们将解析一个本地 HTML 文件。 我们使用重载的 Jsoup.parse 方法,该方法将 File 对象作为其第一个参数。

src/main/resources/index.html
<!DOCTYPE html>
<html>
    <head>
        <title>My title</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="mydiv">Contents of a div element</div>
    </body>
</html>

对于本示例,我们使用上面的 HTML 文件。

Main.java
import java.io.File;
import java.io.IOException;
import java.util.Optional;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

void main() throws IOException {

    String fileName = "src/main/resources/index.html";

    Document doc = Jsoup.parse(new File(fileName), "utf-8");
    Optional<Element> divTag = Optional.ofNullable(doc.getElementById("mydiv"));

    divTag.ifPresent(e -> System.out.println(e.text()));
}

该示例解析 index.html 文件,该文件位于 src/main/resources/ 目录中。

Document doc = Jsoup.parse(new File(fileName), "utf-8"); 

我们使用 Jsoup.parse 方法解析 HTML 文件。

Optional<Element> divTag = Optional.ofNullable(doc.getElementById("mydiv"));

使用文档的 getElementById 方法,我们通过其 ID 获取元素。

divTag.ifPresent(e -> System.out.println(e.text()));

标签的文本使用元素的 text 方法检索。

读取网站的标题

在以下示例中,我们抓取并解析一个网页并检索标题元素的内容。

Main.java
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

void main() throws IOException {
    
    String url = "https://webcode.me";
    
    Document doc = Jsoup.connect(url).get();
    String title = doc.title();
    System.out.println(title);
}

在代码示例中,我们读取指定网页的标题。

Document doc = Jsoup.connect(url).get();

Jsoup 的 connect 方法创建到给定 URL 的连接。 get 方法执行 GET 请求并解析结果;它返回一个 HTML 文档。

String title = doc.title();

使用文档的 title 方法,我们获取 HTML 文档的标题。

读取网页

下一个示例检索网页的 HTML 源代码。

Main.java
import java.io.IOException;
import org.jsoup.Jsoup;

void main() throws IOException {

    String webPage = "https://webcode.me";
    String html = Jsoup.connect(webPage).get().html();

    System.out.println(html);
}

该示例打印网页的 HTML。

String html = Jsoup.connect(webPage).get().html();

html 方法返回元素的 HTML;在我们的例子中是整个文档的 HTML 源代码。

元数据信息

HTML 文档的元信息提供有关网页的结构化元数据,例如其描述和关键字。

Main.java
import java.io.IOException;
import java.util.Optional;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

void main() throws IOException {

    String url = "https://jsoup.org";
    Document doc = Jsoup.connect(url).get();

    Optional<Element> el1 = Optional.ofNullable(doc.select("meta[name=description]").first());
    el1.ifPresent(e -> System.out.println(e.attr("content")));

    Optional<Element> el2 = Optional.ofNullable(doc.select("meta[name=keywords]").first());
    el2.ifPresent(e -> System.out.println(e.attr("content")));
}

该代码示例检索有关指定网页的元信息。

Optional<Element> el2 = Optional.ofNullable(doc.select("meta[name=keywords]").first());
el2.ifPresent(e -> System.out.println(e.attr("content")));

文档的 select 方法查找与给定查询匹配的元素。 first 方法返回第一个匹配的元素。 使用 attr 方法,我们获取 content 属性的值。 我们使用 Optional 来处理可能的 NullPointerException。

获取所有标签

要获取所有标签,我们将 * 字符传递给 select 方法。

Main.java
import org.jsoup.Jsoup;

import java.io.File;
import java.io.IOException;

void main() throws IOException {

    var fileName = "src/main/resources/words.html";
    var myFile = new File(fileName);

    var doc = Jsoup.parse(myFile, "UTF-8");
    var all = doc.body().select("*");

    all.forEach(e -> System.out.println(e.tagName()));
}

我们从 words.html 文档中获取所有标签。

var all = doc.body().select("*");

我们获取所有元素。

all.forEach(e -> System.out.println(e.tagName()));

我们遍历所有元素,并使用 tagName 打印它们的标签名称。

text 方法

text 方法获取此元素及其所有子元素的组合文本。 空格被规范化和修剪。

Main.java
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.File;
import java.io.IOException;
import java.util.Optional;

void main() throws IOException {

    var fileName = "src/main/resources/words.html";
    var myFile = new File(fileName);

    var doc = Jsoup.parse(myFile, "UTF-8");

    System.out.println(doc.text());

    System.out.println("---------------------------");
    System.out.println(doc.body().text());

    System.out.println("---------------------------");
    Optional<Element> e1 = Optional.ofNullable(doc.select("body>p").first());
    e1.ifPresent(e -> System.out.println(e.text()));

    System.out.println("---------------------------");
    Optional<Element> e2 = Optional.ofNullable(doc.select("body>ul").first());
    e2.ifPresent(e -> System.out.println(e.text()));

    System.out.println("---------------------------");
    e2.ifPresent(e -> {
        Elements lis = e.children();

        Optional<Element> ch1 = Optional.ofNullable(lis.first());
        ch1.ifPresent(ce -> System.out.println(ce.text()));

        Optional<Element> ch2 = Optional.ofNullable(lis.last());
        ch2.ifPresent(ce -> System.out.println(ce.text()));
    });
}

在示例中,我们从整个文档、正文、段落、无序列表以及第一个和最后一个列表项中获取文本数据。

Document title List of words dark smart cloud park cup water rock footer for words
---------------------------
List of words dark smart cloud park cup water rock footer for words
---------------------------
List of words
---------------------------
dark smart cloud park cup water rock
---------------------------
dark
rock

修改文本

重载的 text 方法设置指定元素的文本。

Main.java
import org.jsoup.Jsoup;

void main() {

    String htmlString = """
            <html><head><title>My title</title></head>
            <body>Body content</body></html>""";

    var doc = Jsoup.parse(htmlString);
    doc.body().text("Lorem ipsum dolor sit amet");

    System.out.println(doc);
}

在示例中,我们更改 body 标签内的文本。

修改文档

有多种方法可以修改 HTML 文档。 例如,append 方法附加一个标签,prepend 方法将一个标签前置到一个元素。

Main.java
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import java.util.Optional;


void main() {

    String htmlString = """
            <html><head><title>My title</title></head>
            <body></body></html>""";

    var doc = Jsoup.parse(htmlString);
    Optional<Element> bodyEl = Optional.ofNullable(doc.select("body").first());

    bodyEl.ifPresent(e -> {
        e.append("<p>hello there!</p>");
        e.prepend("<h1>Heading</h1>");
    });

    System.out.println(doc);
}

在示例中,我们将 h1p 标签添加到文档中。

<html>
 <head>
  <title>My title</title>
 </head> 
 <body>
  <h1>Heading</h1>
  <p>hello there!</p>
 </body>
</html>

解析链接

下一个示例从 HTML 页面解析链接。

Main.java
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

void main() throws IOException {
    
    String url = "https://jsoup.org";

    Document document = Jsoup.connect(url).get();
    Elements links = document.select("a[href]");
    
    for (Element link : links) {
        
        System.out.println("link : " + link.attr("href"));
        System.out.println("text : " + link.text());
    }
}

在示例中,我们连接到一个网页并解析其所有链接元素。

Elements links = document.select("a[href]");

要获取链接列表,我们使用文档的 select 方法。

清理 HTML 数据

JSoup 提供了清理 HTML 数据的方法。

Main.java
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Cleaner;
import org.jsoup.safety.Safelist;


void main() {

    String htmlString = """
            <html><head><title>My title</title></head>
            <body><center>Body content</center></body></html>
            """;

    boolean valid = Jsoup.isValid(htmlString, Safelist.basic());

    if (valid) {

        System.out.println("The document is valid");
    } else {

        System.out.println("The document is not valid.");
        System.out.println("Cleaned document");

        Document dirtyDoc = Jsoup.parse(htmlString);
        Document cleanDoc = new Cleaner(Safelist.basic()).clean(dirtyDoc);

        System.out.println(cleanDoc.html());
    }
}

在示例中,我们清理并清除 HTML 数据。

String htmlString = """
        <html><head><title>My title</title></head>
        <body><center>Body content</center></body></html>
        """;

HTML 字符串包含已弃用的 center 元素。

boolean valid = Jsoup.isValid(htmlString, Safelist.basic());

isValid 方法确定字符串是否为有效的 HTML。 白名单是可以传递到清理器的 HTML(元素和属性)的列表。 Whitelist.basic 定义了一组基本的干净 HTML 标签。

Document dirtyDoc = Jsoup.parse(htmlString);
Document cleanDoc = new Cleaner(Safelist.basic()).clean(dirtyDoc);

Cleaner 的帮助下,我们清理了脏 HTML 文档。

The document is not valid.
Cleaned document
<html>
 <head></head>
 <body>
  Body content
 </body>
</html>

我们可以看到 center 元素已被删除。

来源

Jsoup 文档

本教程专门介绍 JSoup HTML 解析器。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。 我自 2007 年以来一直在撰写编程文章。到目前为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有Java教程