PDF转Markdown工具(pdf-inspector)
这个技能解决什么问题
绝大多数 PDF 处理工作流的浪费都发生在没判断就上 OCR:一个 200 页的文本型 PDF 送进 OCR 要几分钟,而它其实 0.5 秒就能直接抽干净文本。
这个技能的核心是先分类、再提取、只把真正需要的页分流出去:
PDF 进来
→ 毫秒级分类(text_based / scanned / image_based / mixed)
→ text_based? → 本地直抽 Markdown,几十毫秒,零 OCR 成本
→ 有 pages_needing_ocr? → 只把这些页号交出去做 OCR,其余照抽
引擎是 Firecrawl 的 pdf-inspector(Rust + PyO3)。
在 opendataloader-bench 200 篇语料上总分 0.875、表格 TEDS 0.814、阅读顺序 0.915,均为同类本地引擎最高。
和其他 PDF 技能的分工(重要,别用错)
| 需求 | 该用谁 |
|---|---|
| PDF → Markdown / 提表格 / 高速批量体检 / 判扫描件 | 本技能 |
| 改 PDF 文字、合并、拆分、加密、水印、转 Word | pdf-toolkit |
| 扫描件/图片 OCR 成可搜索文本 | pdf-image-text-extractor 或 pdf-toolkit 的 OCR 分支 |
| 只是读 PDF 回答问题 | workbuddy-pdf |
本技能不做:不写 PDF、不合并拆分、不做 OCR 本身。
扫描页它只负责准确告诉你是哪几页,识别交给上层 OCR 技能。
环境
- Python:
C:/Users/Administrator/.workbuddy/binaries/python/envs/default/Scripts/python.exe - 依赖:
pdf-inspector==1.25.2(预编译 wheel,不需要 Rust 工具链) - 脚本:
<本技能>/scripts/pi_cli.py
首次安装(脚本会检测,缺失时退出码 3 并提示):
pip install pdf-inspector==1.25.2
装到 WorkBuddy 的默认解释器(其它环境可能不生效):
"C:/Users/Administrator/.workbuddy/binaries/python/envs/default/Scripts/python.exe" -m pip install pdf-inspector==1.25.2
纯提取路径不依赖 PDFium / ONNX,也不会联网下载模型。
PY="C:/Users/Administrator/.workbuddy/binaries/python/envs/default/Scripts/python.exe"
PI="C:/Users/Administrator/.workbuddy/skills/pdf-inspector-extract/scripts/pi_cli.py"
所有子命令都输出 JSON({"ok": true/false, "data": {...}}),退出码:
0 成功 / 2 参数或文件问题 / 3 未装库 / 4 没提到正文(扫描件)/ 5 运行异常。
子命令
1. info — 快速分类(首选,先跑这个)
"$PY" "$PI" info a.pdf
返回 pdf_type、confidence、page_count、pages_needing_ocr、
pages_with_tables、pages_with_columns、has_encoding_issues、cmap_gaps,
以及 title/author/producer 等元数据。通常 2–10ms。
决策依据:
- pdf_type=text_based 且 pages_needing_ocr=[] → 直接走 md,别碰 OCR
- has_encoding_issues=true 或 cmap_gaps 里 unmapped 占比高 → 字体编码坏了,
抽出来的字可能是乱码或 `,**考虑 OCR 兜底**
-pages_needing_ocr` 非空 → 记下这些页号,混合件只对这些页做 OCR
2. md — 提取 Markdown(主用法)
"$PY" "$PI" md a.pdf -o out.md --json
"$PY" "$PI" md a.pdf --pages "1,3,5-10"
默认写到同目录 a.md。--json 同时落一个 a.meta.json(含分类结果和统计)。
正文为空时退出码 4,并带回 pdf_type 和 pages_needing_ocr,便于上层直接转 OCR。
输出质量参考(实测调研报告 PDF):
|时间|实测|预测|下界|上界|
|---|---|---|---|---|
|7|17.9|17.90|17.90|17.90|
**Figure 13.3. Graph of Projection Estimates**
表格结构、图注加粗、下划线(<u>)、段落顺序都能还原。
3. text — 只要纯文本
"$PY" "$PI" text a.pdf -o a.txt
不需要结构、只要文字的场合用它,比 md 更快。
4. pages — 逐页 Markdown + 每页是否需要 OCR
"$PY" "$PI" pages a.pdf --pages "1,10" --preview 200
"$PY" "$PI" pages a.pdf --full # 返回完整正文
每页返回 {page, chars, needs_ocr, ocr_reason, markdown}(page 为 1 起)。
用于混合件:先把能抽的页抽出来,再把 needs_ocr=true 的页号交给 OCR。
5. items — 带坐标的文字块(排版分析)
"$PY" "$PI" items a.pdf -o items.json
每个文字块返回 x/y/w/h(PDF 点,原点为可见页框左下角,y 向上)、rotation、
font、font_size、bold/italic、font_weight、fill(sRGB 填充色)、
underline/strikeout、baseline_shift(上下标偏移)。
这组数据能做什么:判断标题层级、定位某段文字位置、识别高亮/彩色标注、
逆向表格坐标、区分正文与页眉页脚。
6. batch — 批量体检(省时利器)
"$PY" "$PI" batch ./pdf_dir -o report.csv --dump-md ./md_out --quiet
遍历目录下所有 PDF,逐篇记录类型/置信度/页数/字符数/耗时/表格页/需 OCR 页,
输出 Excel 可直接打开的 CSV(utf-8-sig)。
一次性给出一批文件里哪些能直抽、哪些要 OCR、哪些抽不出东西。
典型工作流
A. 单篇转 Markdown(最常见)
"$PY" "$PI" info a.pdf # 先看类型
"$PY" "$PI" md a.pdf --json # 再抽
info 显示扫描件就别抽了,直接转 OCR 技能,省一次无用功。
B. 混合件分流(扫描+文本混在一起)
"$PY" "$PI" pages a.pdf --full > pages.json
把 needs_ocr=false 的页拼成正文,needs_ocr=true 的页号交给
pdf-toolkit / pdf-image-text-extractor 做 OCR,最后按页序合并。
这样 100 页里只有 5 页是扫描时,OCR 成本降到 5%。
C. 批量筛查大量 PDF
先 batch 出报告,再按 pdf_type 分组处理:
文本型批量 md,扫描型整批交 OCR。先分类后处理,永远比直接全量 OCR 省。
D. 抽出来发现是乱码
info 里 has_encoding_issues=true 或正文含大量 `` → 大概率是 ToUnicode CMap 缺失
(老扫描仪、某些国产排版软件导出的 PDF 常见)。此时换 OCR 路径,别硬修字体。
已知坑(实测)
| 坑 | 说明 |
|---|---|
| 页码基准不一致 | 上游 extract_pages_markdown 的 pages 参数是 0 起,而 process_pdf / extract_text_with_positions 是 1 起。本技能 CLI 已统一成 1 起,直接调库时务必注意 |
| 加密 PDF | 直接抛 ValueError: PDF is encrypted,本技能会转成结构化错误并提示先解密 |
| OCR 别走本技能 | process_pdf_with_ocr 需要外部 PDFium/ONNX,没装会报 failed to load PDFium;纯提取用不到它 |
| 大文件耗时线性 | 430 页/130 万字符约 54 秒(~126ms/页),属正常。速度基准里的 0.47s/200篇指小文档 |
| 表格识别不保证 | 无框线表格靠启发式对齐推断,复杂合并单元格可能需人工校 |
参考
- 上游仓库: https://github.com/firecrawl/pdf-inspector
- PyPI: https://pypi.org/project/pdf-inspector/
- Python API 全量签名:
<本技能>/references/python-api.md