Java 提取 HTML 文本内容:两种轻量级实现方案对比

35 阅读5分钟

在日常的 Java 开发中,我们经常会遇到处理 HTML 内容的场景。无论是做简单的网页数据抓取、处理富文本编辑器提交的内容,还是对文档进行全文索引,从 HTML 中剥离标签、提取纯文本都是一个绕不开的基础需求。

HTML 作为一种标记语言,包含了大量用于控制样式的标签(如 <div><span><p>)以及脚本代码。如果我们直接使用正则表达式去处理这些嵌套复杂的标签,不仅代码容易出错,而且维护成本较高。

本文将介绍两种处理思路:一种是利用第三方文档处理库(以 Spire.Doc for Java 为例)将 HTML 作为文档解析;另一种是主流的轻量级 HTML 解析器方案。通过对比,帮助开发者根据自身场景做出合理的技术选型。

环境准备

  • JDK 1.8 及以上版本
  • Maven 项目管理工具

1. 为什么不能直接用正则表达式?

在处理 HTML 转文本时,正则表达式是最直观的想法,但它存在明显的局限性:

  • 无法处理嵌套标签:例如 <div>a<p>b</p>c</div>,正则很难正确匹配层级关系。
  • 容易误匹配:标签内的属性、注释、CDATA 等特殊结构容易干扰匹配结果。
  • 维护困难:面对不同来源的 HTML(如缺失闭合标签、大小写不一致),正则规则会变得臃肿且脆弱。

因此,推荐使用成熟的解析方案。

2. 方案一:文档转换器方式

该方案借助第三方文档处理库,将 HTML 映射为文档对象模型,然后调用获取文本的方法。

2.1 项目依赖配置

pom.xml 中添加如下依赖:

<repositories>
    <repository>
        <id>com.e-iceblue</id>
        <name>e-iceblue</name>
        <url>https://repo.e-iceblue.com/nexus/content/groups/public/</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>e-iceblue</groupId>
        <artifactId>spire.doc</artifactId>
        <version>14.3.1</version>
    </dependency>
</dependencies>

:该库提供免费版和商业版。对于基础的文本提取需求,免费版通常足够。

2.2 核心实现

import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import java.io.FileWriter;
import java.io.IOException;

public class HtmlTextExtractor {

    public static void main(String[] args) {
        // 1. 实例化 Document 对象
        Document document = new Document();

        // 2. 加载 HTML 文件(指定格式为 Html)
        document.loadFromFile("input.html", FileFormat.Html);

        // 3. 提取纯文本内容
        String extractedText = document.getText();

        // 4. 输出或保存结果
        System.out.println("提取的文本内容:\n" + extractedText);

        // 可选:保存到 txt 文件
        try (FileWriter writer = new FileWriter("output.txt")) {
            writer.write(extractedText);
            System.out.println("\n文本已成功保存到 output.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

代码解析

  • Document 类通常用于处理 Word 文档,但它同样支持 FileFormat.Html 格式。加载时,库内部会解析 HTML 标签,将其映射为段落、表格等文档元素。
  • getText() 方法遍历文档树,提取所有可见文本,同时跳过控制字符和标签代码。

2.3 处理 URL 网页

如果需要直接抓取线上的网页内容,可以结合 Java 原生的 HttpClient 获取网页源代码后再解析:

import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;

public class UrlTextExtractor {

    public static void main(String[] args) {
        String urlStr = "https://example.com";
        
        try {
            String htmlPath = fetchHtmlFromUrl(urlStr, "temp.html");
            Document doc = new Document();
            doc.loadFromFile(htmlPath, FileFormat.Html);
            String text = doc.getText();
            System.out.println(text);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String fetchHtmlFromUrl(String urlString, String savePath) throws Exception {
        URL url = new URL(urlString);
        URLConnection conn = url.openConnection();
        conn.setConnectTimeout(5000);
        conn.setRequestProperty("User-Agent", "Mozilla/5.0");
        
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
             FileWriter writer = new FileWriter(savePath)) {
            String line;
            while ((line = reader.readLine()) != null) {
                writer.write(line);
                writer.write("\n");
            }
        }
        return savePath;
    }
}

注意:解析 URL 时需遵守目标网站的 robots.txt 协议及数据获取的合规性要求。

3. 方案二:轻量级 HTML 解析器方式(以 Jsoup 为例)

相比文档转换方式,Jsoup 是专门为 HTML 解析设计的轻量级库,在社区中使用更为广泛。

3.1 依赖配置

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

3.2 核心实现

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.File;

public class JsoupExtractor {

    public static void main(String[] args) throws Exception {
        // 加载 HTML 文件
        Document doc = Jsoup.parse(new File("input.html"), "UTF-8");
        
        // 提取纯文本(自动去除标签)
        String text = doc.text();
        
        System.out.println(text);
    }
}

Jsoup 的 text() 方法会递归获取所有可见文本,并用空格连接块级元素的内容,输出结果更适合阅读。

3.3 直接解析 URL

Jsoup 内置了网络请求能力,代码更为简洁:

Document doc = Jsoup.connect("https://example.com")
    .userAgent("Mozilla/5.0")
    .timeout(5000)
    .get();
String text = doc.text();

4. 方案对比与适用场景

维度文档转换方式(Spire.Doc)轻量级解析器(Jsoup)
设计定位文档处理(Word、HTML 等)HTML 解析专用
API 复杂度较高(需了解 Document 模型)简单直观
HTML 容错能力较强很强(业界公认)
网络请求需自行实现内置支持
依赖体积较大(包含文档处理能力)小巧(约 500KB)
扩展性可转为 Word 等其他格式聚焦 HTML/CSS 选择器

各自的适用场景

  • 文档转换方式:适合需要同时处理 Word 文档和 HTML 文件的场景,或希望统一文档处理逻辑的项目。
  • 轻量级解析器:适合纯 HTML 提取、网页抓取、需要按 CSS 选择器提取特定元素内容的场景。

5. 两种方案的共同局限性

无论选择哪种方案,在提取纯文本时都需要注意以下几点:

  1. 格式信息丢失:提取结果仅包含文本,原 HTML 中的表格布局、字体大小、颜色、图片链接等富媒体信息均会丢失。
  2. 编码处理:如果 HTML 未正确声明 charset,可能需要手动指定编码,否则可能出现中文乱码。
  3. 大文件性能:对于数十 MB 的超大 HTML 文件,两种方案的内存占用都会显著上升,建议分块或流式处理。

6. 总结

从 HTML 中提取纯文本是 Java 开发中的常见需求。本文对比了两种可行的技术方案:

文档转换方式以 Spire.Doc for Java 为例,其特点是将 HTML 视为文档对象进行解析,API 封装程度较高,但依赖体积偏大,适合需要统一处理 Word 和 HTML 格式的项目。

轻量级解析器以 Jsoup 为例,它是专门为 HTML 设计的工具,API 简洁、HTML 容错能力强,并且内置了网络请求支持,在社区中使用广泛,是纯文本提取场景下的主流选择。

开发者可以根据项目现有依赖、体积敏感度以及是否需要额外的 HTML 操作(如选择器提取、DOM 修改)来选择合适的方案。如果项目仅需简单的去标签处理,Jsoup 可能是更轻量的选择;如果项目中已经引入了文档处理相关依赖,则可以直接复用文档转换方式。