You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Apache Tika将通用HTML转为类阅读器视图的层级章节?

问题描述

我希望将PDF、HTML等文档转换为可在Elasticsearch等检索数据库中可靠检索的格式。为优化长文本检索效果,需将长文本拆分为层级章节结构(示例如下):

{
    "sections": {
        "title": "Stack Overflow",
        "sections": [
            {
                "text": "Stack Overflow is a question and answer website for professional and enthusiast programmers. It is the flagship site of the Stack Exchange Network."
            },
            {
                "title": "History",
                "sections": [
                    {
                        "text": "The website was created by Jeff Atwood and Joel Spolsky in 2008"
                    },
                    {
                        "title": "Security breach",
                        "text": "In early May 2019, an update was deployed to Stack Overflow's development version."
                    }
                ]
            }
        ]
    }
}

已知Apache Tika可将PDF转换为HTML,但Tika通常依赖固定文档结构,而我的文档无统一可预测结构。类似Mozilla Readability的阅读器视图插件可通过启发式方法格式化HTML文档,请问如何借助Apache Tika将通用HTML文档转换为上述层级章节结构,实现类似阅读器视图的效果?


解决方案

1. 核心思路:Tika + 启发式内容筛选

Apache Tika本身对无结构HTML的智能章节提取支持有限,需要结合阅读器模式的启发式逻辑,分两步处理:先提取并净化HTML核心内容,再基于标题层级构建嵌套章节。

2. 具体实现步骤

步骤一:用Tika提取HTML原始内容(含PDF转HTML)

  • 若处理PDF,先用Tika的PDFParser将其转换为HTML格式;若直接处理HTML,用HTMLParser读取原始文档,保留DOM结构和元素元信息(如标签类型、样式)。
  • 示例Java代码:
InputStream input = new FileInputStream("target.html");
ContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();
HtmlParser parser = new HtmlParser();
parser.parse(input, handler, metadata);
String rawHtml = handler.toString();

步骤二:净化HTML,提取核心内容(模拟阅读器视图)

直接用Tika得到的HTML包含导航、侧边栏、页脚等无关内容,需先净化:

  • 搭配Readability类库(如Java的Readability4J),传入Tika输出的原始HTML,提取出仅含正文的简化HTML。该工具通过文本密度、元素位置等启发式规则过滤冗余内容,逻辑和阅读器视图一致。
  • 也可自定义DOM分析:通过Tika的DOM解析能力遍历HTML节点,计算每个区块的文本占比,保留文本密集的核心区块,过滤导航栏、广告等元素。

步骤三:基于标题层级构建嵌套章节

对净化后的核心HTML进行解析,构建目标层级结构:

  • 跟踪HTML中的h1-h6标签,按层级建立嵌套关系:h1为顶级章节,h2作为h1的子章节,以此类推。
  • 将相邻的段落(p标签内容)归到最近的父标题下,生成符合要求的JSON结构。
  • 示例逻辑伪代码:
current_sections = []
current_level = 0
root_section = {"sections": []}

for element in cleaned_html_elements:
    if element.tag in ['h1','h2','h3','h4','h5','h6']:
        level = int(element.tag[-1])
        # 调整当前章节层级
        while current_level >= level:
            current_sections.pop()
            current_level -= 1
        new_section = {"title": element.text.strip(), "sections": []}
        if current_sections:
            current_sections[-1]["sections"].append(new_section)
        else:
            root_section["sections"].append(new_section)
        current_sections.append(new_section)
        current_level = level
    elif element.tag == 'p' and element.text.strip():
        text_section = {"text": element.text.strip()}
        if current_sections:
            current_sections[-1]["sections"].append(text_section)
        else:
            root_section["sections"].append(text_section)

3. 扩展处理:非标准标题场景

部分无结构文档用div等标签模拟标题(无h1-h6),可通过Tika提取的元素样式信息判断:

  • 读取元素的style属性,筛选出字体大小大于普通文本、且为加粗的元素,将其视为对应层级的标题,再按上述逻辑构建章节。

内容的提问来源于stack exchange,提问作者rbhalla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 18:20:34