CH2_01_unstructured_example

2248 字
11 分钟
CH2_01_unstructured_example

1. 创建简单示例#

from unstructured.partition.auto import partition
# PDF文件路径
pdf_path = "../../data/C2/pdf/rag.pdf"
# 使用Unstructured加载并解析PDF文档
elements = partition(
filename=pdf_path,
content_type="application/pdf"
)
# 打印解析结果
print(f"解析完成: {len(elements)} 个元素, {sum(len(str(e)) for e in elements)} 字符")

输出为:

解析完成: 279 个元素, 7500 字符

partition 函数参数解析:

  • filename: 文档文件路径,支持本地文件路径;
  • content_type: 可选参数,指定MIME类型(如”application/pdf”),可绕过自动文件类型检测;
  • file: 可选参数,文件对象,与 filename 二选一使用;
  • url: 可选参数,远程文档 URL,支持直接处理网络文档;
  • include_page_breaks: 布尔值,是否在输出中包含页面分隔符;
  • strategy: 处理策略,可选 “auto”、“fast”、“hi_res” 等;
    • auto :优先尝试快速提取文本,如果文本提取效果差就自动降级为 OCR.
    • fast :直接用 PDF 解析器提取 内置文本层,速度快,但不解析图片中的文字;
    • hi_res :高精度模式,先做 OCR,然后再结合布局分析,精度最高;
    • ocr_only :完全忽略 PDF 内置文本层,只靠 OCR 识别所有内容。
  • encoding: 文本编码格式,默认自动检测。

partition 函数使用自动文件类型检测,内部会根据文件类型路由到对应的专用函数(如 PDF 文件会调用partition_pdf)。如果需要更专业的 PDF 处理,可以直接使用 from unstructured.partition.pdf import partition_pdf,它提供更多 PDF 特有的参数选项,如 OCR 语言设置、图像提取、表格结构推理等高级功能,同时性能更优。

在实际应用中,针对 pdf 的处理,目前更多选用的是 PaddleOCR、MinerU 等模型或工具。

# 统计元素类型
from collections import Counter
types = Counter(e.category for e in elements)
print(f"元素类型: {dict(types)}")

输出为:

元素类型: {'Header': 22, 'Title': 195, 'UncategorizedText': 41, 'NarrativeText': 3, 'Footer': 15, 'ListItem': 3}
# 显示所有元素
print("\n所有元素:")
for i, element in enumerate(elements, 1):
print(f"Element {i} ({element.category}):")
print(element)
print("=" * 60)

输出为:

所有元素:
Element 1 (Header):
网页
============================================================
Element 2 (Header):
新闻
============================================================
Element 3 (Header):
贴吧
============================================================
Element 4 (Header):
知道
============================================================
Element 5 (Header):
网盘
============================================================
Element 6 (Header):
图片
============================================================
Element 7 (Header):
视频
============================================================
Element 8 (Header):
地图
...
============================================================
Element 279 (Footer):
HTML to PDF
============================================================

2. 用 partition_pdf 替换当前 partition 函数#

我们使用 partition_pdf 替换当前 partition 函数并分别尝试用 hi_resocr_only 进行解析,观察输出结果有何变化。

from unstructured.partition.pdf import partition_pdf
# 运行前确保安装 Poppler 和 Tesseract OCR
elements = partition_pdf(
filename=pdf_path,
content_type="application/pdf",
strategy = "ocr_only"
)
# 打印解析结果
print(f"解析完成: {len(elements)} 个元素, {sum(len(str(e)) for e in elements)} 字符")

输出为:

# hi_res 结果
解析完成: 221 个元素, 8265 字符
# ocr_only 结果
解析完成: 137 个元素, 8282 字符

关于元素数量,一般而言是越少越好:

策略元素数原因
fast279(最多)直接读 PDF 文本层,PDF 里每个独立文本对象(哪怕只是”网页”两个字)都算一个元素
hi_res221布局模型会把相邻小文本合并到同一区域,所以元素更少,但结构更合理
ocr_only137(最少)每页是一大块文字 + 标题,碎片化程度最低

fast 的 279 个元素中,有 195 个 Title,很多只是导航栏的碎片(“网页”、“新闻”、“贴吧”……)。hi_res 的布局模型将这些碎片合并成了更大的块。

# 统计元素类型
from collections import Counter
types = Counter(e.category for e in elements)
print(f"元素类型: {dict(types)}")

输出为:

# hi_res 结果
元素类型: {'Image': 22, 'UncategorizedText': 85, 'Header': 4, 'NarrativeText': 68, 'Table': 4, 'FigureCaption': 4, 'Title': 30, 'ListItem': 4}
# ocr_only 结果
元素类型: {'UncategorizedText': 54, 'Title': 55, 'NarrativeText': 27, 'ListItem': 1}

可以看到,在输出的元素类型上,两种策略有很大不同:

类型hi_resocr_only原因
Image✅ 22❌ 无hi_res 有布局检测模型,能识别图片区域;ocr_only 只做 OCR,不分析布局
Table✅ 4❌ 无同上,表格区域由布局模型识别
FigureCaption✅ 4❌ 无图片/表格的标题,也只有布局模型能识别
Header✅ 4❌ 无页面顶部导航栏等
NarrativeText6827hi_res 中布局模型区分了正文和杂项,ocr_only 很多被归入 UncategorizedText
UncategorizedText8554ocr_only 没有布局信息,大量文本无法归类
Title3055ocr_only 中 OCR 识别的短文本片段容易被判为 Title

这主要是由于两种策略不同的流程导致的:

hi_res 流程:
PDF → Poppler 转图片 → 布局检测模型(YOLOX)识区域 → Tesseract OCR 各区域
Image / Table / Header
NarrativeText / Title ...
ocr_only 流程:
PDF → Poppler 转图片 → Tesseract OCR 整页 → 全是文字,无布局标签

可以看到,hi_res 多了一个 布局检测步骤,所以可以区分出 image, table, figure caption 等结构化元素。

# 显示所有元素
print("\n所有元素:")
for i, element in enumerate(elements, 1):
print(f"Element {i} ({element.category}):")
print(element)
print("=" * 60)

输出为:

# hi_res 结果
所有元素:
Element 1 (Image):
============================================================
Element 2 (UncategorizedText):
Bh fe
============================================================
Element 3 (UncategorizedText):
Se «6 Be BR 8H Me OE 6B CR OBS
============================================================
Element 4 (Header):
百度首页 登录 注册
============================================================
Element 5 (UncategorizedText):
0 0 Bai @ Bil | eme22n
============================================================
Element 6 (UncategorizedText):
x
============================================================
Element 7 (UncategorizedText):
进⼊词条
============================================================
Element 8 (UncategorizedText):
全站搜索
...
============================================================
Element 221 (UncategorizedText):
HTML to PDF
============================================================
# ocr_only 结果
所有元素:
Element 1 (UncategorizedText):
Bh fe Se «6 Be BR 8H Me OE 6B CR OBS ESR SR ith
============================================================
Element 2 (Title):
0 0 Bai @ Bil | eme22n x SME | mm
============================================================
Element 3 (NarrativeText):
MBA RAATEABEBANEAAR, VRE A BIDHAE RR O, CEL IERAA: BREN RRMA, ONCE CIRS, LYSE! iFIB>> Bn pias HEAR ALIAS a MAB BAAR RAE > 1 REA i oa E AK ) HR Otte Lew
============================================================
Element 4 (UncategorizedText):
ABB AWARAZ—
============================================================
Element 5 (Title):
MoingSh
============================================================
Element 6 (NarrativeText):
fomieas tat OACe >)
============================================================
Element 7 (NarrativeText):
it =
============================================================
Element 8 (Title):
[= = HEhH - SAR RAGFlow RAF RAMA
...
============================================================
Element 137 (UncategorizedText):
Explore our developer-friendly HTML to PDF API Printed using PDFCrowd H to PDF
============================================================

从具体识别到的元素来看,我们可以发现 ocr_only 对中文的效果很差,比如 Bh, fe 等完全就是乱码,甚至英文部分的 MBA, RAATEABEBANEAAR 也严重变形。

这主要是 tesseract 默认使用英文语言包导致的,所以对于我们的示例(中文 PDF),tesseract 几乎无法正确识别。

对此,我们可以添加 language 参数(记得下载 tesseract 的中文语言包):

elements = partition_pdf(
filename=pdf_path,
strategy="ocr_only", # ocr_only, hi_res
languages=["chi_sim"] # 简体中文
)

增加语言包后的输出为:

# hi_res 的结果
解析完成: 241 个元素, 8224 字符
# ocr_only 的结果
解析完成: 143 个元素, 12247 字符

首先我们来关注 hi_res 的变化。中文包让 OCR 能在布局模型划分的区域内识别出更多独立文本块,所以元素数略微增加。之前因乱码被合并或丢弃的文本现在被正确提取。而字符数反而有所减少,这是因为 OCR 正确识别中文后,同一个面积的区域内,中文字符比英文乱码字符更少(一个汉字 vs 一串”Xe «6 Be BR…”),所以总数反而略降。

可以看到,在加装了中文语言包后,ocr_only 解析出的字符几乎暴涨了 50%,从 8282 -> 12247. 这是因为英文 OCR 时,中文段落被识别为一堆乱码字符,很多”字”根本没被识别出来。中文包生效后,每个汉字都被正确识别,所以总字符数大幅增加。

# hi_res 的结果
元素类型: {'Image': 21, 'UncategorizedText': 106, 'Header': 4, 'NarrativeText': 68, 'Table': 4, 'FigureCaption': 4, 'Title': 30, 'ListItem': 4}
# ocr_only 的结果
元素类型: {'Title': 52, 'NarrativeText': 27, 'UncategorizedText': 54, 'ListItem': 10}

hi_resUncategorizedText 有所增加,这些新增的 UncategorizedText 主要来自导航栏碎片——之前因为乱码被丢弃或归为其他类型,现在被正确识别并保留。

在加装中文语言包后,ocr_only 也成功识别出了更多的结构化信息,例如列表项(ListItem 1 -> 10),之前因为乱码而根本无法判定。

# hi_res 的结果
所有元素:
Element 1 (Image):
============================================================
Element 2 (UncategorizedText):
国 页
============================================================
Element 3 (UncategorizedText):
新 闻 _
============================================================
Element 4 (UncategorizedText):
============================================================
Element 5 (UncategorizedText):
贴吧
============================================================
Element 6 (UncategorizedText):
知 道
============================================================
Element 7 (UncategorizedText):
网盘
============================================================
Element 8 (UncategorizedText):
图片
...
============================================================
Element 241 (UncategorizedText):
HTML to PDF
============================================================
# ocr_only 的结果
所有元素:
Element 1 (Title):
国 页 新 闻 _ 贴 吧 知 道
============================================================
Element 2 (Title):
百 科 百 度 首 页 “ 登 录 “ 注 册
============================================================
Element 3 (Title):
.... Baidb 百 租 | 8458 办 x
============================================================
Element 4 (Title):
全 站 搜 索 ‖ 帝 助
============================================================
Element 5 (NarrativeText):
近 期 有 不 法 分 子 冒 兆 百 度 百 科 客 方 人 员 , 以 删 除 词 条 为 申 姚 防 并 敌 许 关 企 业 , 在 此 严 正 声 明 : 百 度 百 科 是 免 资 缉 辑 平 台 , 绝 不 存 在 收 费 代 编 服 务 , 请 勿 上 当 受 腾 ! 详 情 >>
============================================================
Element 6 (UncategorizedText):
首 页 秒 懂 百 科 特 色 百 科 知 识 专 题 加 入 百 科 百 科 团 队 权 威 合 作
============================================================
Element 7 (Title):
《 索 增 强 生 成 。m
============================================================
Element 8 (Title):
大 模 型 前 治 技 术 之 一
...
============================================================
Element 143 (NarrativeText):
Printed using PDFCrowd H to PDF
============================================================

hi_res 在实际解析出的元素上变化不大,因为 hi_res 的元素类型靠的是布局模型(YOLOX),语言包只影响 OCR 文字质量,不影响区域检测,所以类型分布变化不大。

可以很明显地看出,加装了中文语言包后,ocr_only 实际解析出的内容从天书变成了可读的中文。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

CH2_01_unstructured_example
https://datawhalechina.github.io/all-in-rag/#/chapter1/03_get_start_rag
作者
HAC
发布于
2026-06-16
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
HAC
观之非易,行且克难
Greetings
欢迎来到我的博客!这里主要分享我的学习笔记与兴趣爱好。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
32
分类
5
标签
13
总字数
79,889
运行时长
0
最后活动
0 天前

文章目录