Skip to main content
将 HTML 文档分割成可管理的块对于各种文本处理任务至关重要,例如自然语言处理、搜索索引等。在本指南中,我们将探讨 LangChain 提供的三种不同的文本分割器,您可以使用它们来有效地分割 HTML 内容: 这些分割器中的每一个都有其独特的功能和用例。本指南将帮助您理解它们之间的差异,为什么您可能选择其中一个而不是其他,以及如何有效地使用它们。

分割器概述

HTMLHeaderTextSplitter

当您希望根据文档的标题保留其层次结构时,此分割器非常有用。
描述:基于标题标签(例如 <h1><h2><h3> 等)分割 HTML 文本,并为每个与给定块相关的标题添加元数据。 功能
  • 在 HTML 元素级别分割文本。
  • 保留编码在文档结构中的上下文丰富信息。
  • 可以逐个元素返回块,或组合具有相同元数据的元素。

HTMLSectionSplitter

当您希望将 HTML 文档分割成较大的部分(如 <section><div> 或自定义定义的部分)时,此分割器非常有用。
描述:类似于 HTMLHeaderTextSplitter,但侧重于根据指定的标签将 HTML 分割成部分。 功能
  • 使用 XSLT 转换来检测和分割部分。
  • 内部使用 RecursiveCharacterTextSplitter 处理较大的部分。
  • 考虑字体大小来确定部分。

HTMLSemanticPreservingSplitter

当您需要确保结构化元素不会被分割到不同的块中,从而保留上下文相关性时,此分割器是理想的选择。
描述:将 HTML 内容分割成可管理的块,同时保留重要元素(如表格、列表和其他 HTML 组件)的语义结构。 功能
  • 保留表格、列表和其他指定的 HTML 元素。
  • 允许为特定 HTML 标签定义自定义处理器。
  • 确保文档的语义含义得以保持。
  • 内置规范化与停用词移除

选择合适的分割器

  • 使用 HTMLHeaderTextSplitter 的情况:您需要根据 HTML 文档的标题层次结构进行分割,并保留关于标题的元数据。
  • 使用 HTMLSectionSplitter 的情况:您需要将文档分割成更大、更通用的部分,可能基于自定义标签或字体大小。
  • 使用 HTMLSemanticPreservingSplitter 的情况:您需要将文档分割成块,同时保留表格和列表等语义元素,确保它们不被分割并保持其上下文。

示例 HTML 文档

让我们使用以下 HTML 文档作为示例:

使用 HTMLHeaderTextSplitter

HTMLHeaderTextSplitter 是一个“结构感知”的文本分割器,它在 HTML 元素级别分割文本,并为每个与给定块“相关”的标题添加元数据。它可以逐个元素返回块,或组合具有相同元数据的块,其目标是 (a) 将相关文本(或多或少)按语义分组,以及 (b) 保留编码在文档结构中的上下文丰富信息。它可以与其他文本分割器一起用作分块管道的一部分。 它类似于用于 Markdown 文件的 MarkdownHeaderTextSplitter 要指定根据哪些标题进行分割,请在实例化 HTMLHeaderTextSplitter 时指定 headers_to_split_on,如下所示。
要返回每个元素及其关联的标题,请在实例化 HTMLHeaderTextSplitter 时指定 return_each_element=True
与上面按标题聚合元素的情况进行比较:
现在每个元素都作为独立的 Document 返回:

如何从 URL 或 HTML 文件分割:

要直接从 URL 读取,请将 URL 字符串传递给 split_text_from_url 方法。 类似地,可以将本地 HTML 文件传递给 split_text_from_file 方法。

如何限制块大小:

HTMLHeaderTextSplitter 基于 HTML 标题进行分割,可以与另一个基于字符长度限制分割的分割器(如 RecursiveCharacterTextSplitter)组合使用。 这可以使用第二个分割器的 .split_documents 方法来完成:

局限性

不同的 HTML 文档之间可能存在相当大的结构差异,虽然 HTMLHeaderTextSplitter 会尝试将所有“相关”标题附加到任何给定的块,但它有时可能会遗漏某些标题。例如,该算法假设了一种信息层次结构,其中标题始终位于关联文本的“上方”节点,即前一个兄弟节点、祖先节点及其组合。在以下新闻文章中(截至本文撰写时),文档的结构使得顶级标题的文本虽然标记为“h1”,但位于一个与我们期望它“位于其上方”的文本元素不同的子树中——因此我们可以观察到“h1”元素及其关联文本未出现在块元数据中(但在适用的情况下,我们确实看到了“h2”及其关联文本):

使用 HTMLSectionSplitter

在概念上与 HTMLHeaderTextSplitter 类似,HTMLSectionSplitter 是一个“结构感知”的文本分割器,它在元素级别分割文本,并为每个与给定块“相关”的标题添加元数据。它允许您按部分分割 HTML。 它可以逐个元素返回块,或组合具有相同元数据的块,其目标是 (a) 将相关文本(或多或少)按语义分组,以及 (b) 保留编码在文档结构中的上下文丰富信息。 使用 xslt_path 提供一个绝对路径来转换 HTML,以便它可以基于提供的标签检测部分。默认是使用 data_connection/document_transformers 目录中的 converting_to_header.xslt 文件。这是为了将 html 转换为更容易检测部分的格式/布局。例如,基于字体大小的 span 可以转换为标题标签,以便被检测为一个部分。

如何分割 HTML 字符串:

如何限制块大小:

HTMLSectionSplitter 可以与其他文本分割器一起用作分块管道的一部分。内部,当部分大小大于块大小时,它使用 RecursiveCharacterTextSplitter。它还考虑文本的字体大小,以根据确定的字体大小阈值判断它是否是一个部分。

使用 HTMLSemanticPreservingSplitter

HTMLSemanticPreservingSplitter 旨在将 HTML 内容分割成可管理的块,同时保留重要元素(如表格、列表和其他 HTML 组件)的语义结构。这确保了这些元素不会被分割到不同的块中,从而导致上下文相关性(如表头、列表标题等)的丢失。 该分割器的核心设计目的是创建上下文相关的块。使用 HTMLHeaderTextSplitter 进行通用递归分割可能会导致表格、列表和其他结构化元素在中间被分割,从而丢失重要上下文并产生不良的块。 HTMLSemanticPreservingSplitter 对于分割包含表格和列表等结构化元素的 HTML 内容至关重要,尤其是在需要保持这些元素完整的情况下。此外,它能够为特定 HTML 标签定义自定义处理器,使其成为处理复杂 HTML 文档的多功能工具。 重要提示max_chunk_size 不是块的绝对最大大小,最大大小的计算发生在保留内容不属于该块时,以确保它不被分割。当我们把保留的数据添加回块中时,块的大小有可能超过 max_chunk_size。这对于确保我们保持原始文档的结构至关重要
注意:
  1. 我们定义了一个自定义处理器来重新格式化代码块的内容
  2. 我们为特定的 HTML 元素定义了一个拒绝列表,以便在预处理阶段分解它们及其内容
  3. 我们故意设置了一个较小的块大小,以演示元素不会被分割

保留表格和列表

在这个例子中,我们将演示 HTMLSemanticPreservingSplitter 如何保留 HTML 文档中的表格和大型列表。块大小将设置为 50 个字符,以说明分割器如何确保这些元素即使超过定义的最大块大小也不会被分割。

解释

在这个例子中,HTMLSemanticPreservingSplitter 确保整个表格和无序列表 (<ul>) 在其各自的块中得以保留。即使块大小设置为 50 个字符,分割器也认识到这些元素不应被分割,并保持它们完整。 这在处理数据表或列表时尤为重要,因为分割内容可能导致上下文丢失或混淆。生成的 Document 对象保留了这些元素的完整结构,确保了信息的上下文相关性得以保持。

使用自定义处理器

HTMLSemanticPreservingSplitter 允许您为特定 HTML 元素定义自定义处理器。某些平台具有自定义 HTML 标签,这些标签不能被 BeautifulSoup 原生解析,当这种情况发生时,您可以利用自定义处理器轻松添加格式化逻辑。 这对于需要特殊处理的元素(如 <iframe> 标签或特定的 ‘data-’ 元素)特别有用。在这个例子中,我们将为 iframe 标签创建一个自定义处理器,将其转换为类似 Markdown 的链接。

解释

在这个例子中,我们为 iframe 标签定义了一个自定义处理器,将其转换为类似 Markdown 的链接。当分割器处理 HTML 内容时,它使用这个自定义处理器来转换 iframe 标签,同时保留表格和列表等其他元素。生成的 Document 对象展示了 iframe 是如何根据您提供的自定义逻辑进行处理的。 重要提示:在保留链接等项目时,您应注意不要在分隔符中包含 .,或者将分隔符留空。RecursiveCharacterTextSplitter 会按句点分割,这会将链接一分为二。确保您提供的是包含 . 的分隔符列表。

使用自定义处理器通过 LLM 分析图像

通过自定义处理器,我们还可以覆盖任何元素的默认处理。一个很好的例子是在分块流程中直接插入对文档中图像的语义分析。 由于我们的函数在发现标签时被调用,我们可以覆盖 <img> 标签并关闭 preserve_images,以插入我们希望嵌入到块中的任何内容。

解释:

通过我们编写的自定义处理器来提取 HTML 中 <img> 元素的特定字段,我们可以使用代理进一步处理数据,并将结果直接插入到我们的块中。重要的是确保 preserve_images 设置为 False,否则将进行 <img> 字段的默认处理。