PDF 结构化提取
与官方 / 同类技能的关系(去重说明,重要)
“PDF 文字/表格/图片提取”是红海能力,anthropics、openai、claude-office、guia-matthieu、
letta、redfox 等官方/社区技能都做,重叠严重。本技能不假装通用提取独家,而是定位为:
> PDF 提取(agent 友好、零广告、扫描走视觉)
与官方工具箱的差异:
- anthropics/skills/pdf:PDF 全家桶(提取 + 合并 + 拆分 + 表单 + 加密 + 水印 + OCR/tesseract),
库栈重(pypdf/pdfplumber/reportlab + qpdf/pdftotext/pdftk)。它是读写全功能箱;本技能纯提取、零写回。 - openai/skills/pdf:偏“渲染 PNG 用视觉审阅版式 + reportlab 生成 PDF”。它重点是看/造 PDF;
本技能重点是抽结构化数据供给 agent 消费。 - 本技能不可替代点:① 干净 JSON 契约(agent 优先,fd 重定向保 stdout 纯净)② 扫描/乱码页走视觉能力、
零 OCR 重依赖 ③ 零广告、零遥测。
任务目标
- 从用户提供的本地 PDF 文件中提取(非改写)内容:
- 文本层:标题/段落,按阅读顺序还原,支持双栏
- 表格:导出为 Markdown(内联)与 CSV,并裁切表格区域存预览 PNG
- 图片:按内容(SHA-256)去重导出,按覆盖面积/宽高比/信息量过滤装饰图,记录 bbox
- 文档大纲(TOC) 与 超链接:提取为结构化字段
- 扫描页 / 乱码页(文字层不可信):渲染为 PNG,交由视觉能力识别并回填
- 输出 Markdown 文件 + 同目录的图片/表格/扫描图,对话中给出简短摘要
适用范围与边界
支持:
- 文字版 PDF、双栏 PDF、含网格/无边框表格的 PDF、含嵌入图片的 PDF
- 纯扫描件 PDF、文字与扫描混合的 PDF
- 文字层乱码的 PDF(如可变字体导出导致复制乱码):自动判为乱码页并交视觉识别
不做(明确拒绝):
- 合并、拆分、旋转、加密、批注、去水印等任何 PDF 写入类操作
- 不调用本地 OCR(不依赖 Tesseract / RapidOCR);扫描/乱码识别走视觉能力
- 不做 PDF 写回、不做 OCR(扫描仍走视觉能力)
- 不安装 Newton 等外部 PDF 技能
使用指引:parse once(解析一次,检索复用)
提取成本主要来自 PyMuPDF 解析。请遵循:
- 运行脚本得到
<文件名>.md后,后续对该 PDF 的问答直接用 grep / 读取 .md,
不要为了“再找某段话”反复重跑脚本。 - 需要表格原始数据用
tables/*.csv;
需要视觉核对扫描页用scans/*.png;需要核对表格版式用tables_preview/*.png。
运行环境
- 唯一依赖:Python 3.8+ 与 PyMuPDF ≥ 1.28.2(仅此一个第三方库,纯 Python,跨平台)。
- 安装依赖(使用客户端自带的任意 Python,无需任何专属运行时):
bash python3 -m pip install "pymupdf>=1.28.2" # Linux / macOS # Windows 上若 python3 不存在,改用 python python -m pip install "pymupdf>=1.28.2" - 脚本位置:相对于本
SKILL.md同级的scripts/extract_pdf.py。
各客户端加载技能后会提供本文件所在目录,请以该目录为基准解析脚本路径
(例如<skill_dir>/scripts/extract_pdf.py),不要写死绝对路径。 - 调用方式:任何能执行 shell 命令的客户端,用其 Python 运行该脚本即可,
与具体客户端(WorkBuddy / Claude Code / Codex 等)无关。
跨客户端安装(通用)
本技能是纯文件结构,把整个 pdf-structured-extractor/ 文件夹复制到目标客户端的
技能目录即可,脚本不读取任何客户端配置,因此同一份文件在所有客户端行为一致:
| 客户端 | 技能目录 |
|---|---|
| WorkBuddy | ~/.workbuddy/skills/pdf-structured-extractor/ |
| Claude Code | ~/.claude/skills/pdf-structured-extractor/ |
| Codex(OpenAI) | ~/.codex/skills/pdf-structured-extractor/(若用 skills-manager,放入其源目录并建符号链接) |
保持内部结构不变:
pdf-structured-extractor/
├── SKILL.md
└── scripts/
└── extract_pdf.py
> 本技能的 frontmatter 以 name + description 为跨客户端通用核心字段(Claude Code / WorkBuddy / Codex 均识别);
> 其余元数据(dependency、version、author 等)为可选补充,不被识别的客户端会直接忽略,不影响功能,
> 因此同一份文件在所有客户端行为一致,无需为不同客户端维护多份。
操作步骤
1. 确认输入与输出目录
- 确认用户已提供本地 PDF 路径(不支持仅给 URL,需先下载到本地)。
- 约定输出目录:与原文件同级的
<原文件名>_extracted\,例如
report.pdf→report_extracted\。也可由用户指定。
2. 运行脚本
将 <skill_dir> 替换为本 SKILL.md 所在目录(各客户端加载技能后会提供该路径)。
python3 "<skill_dir>/scripts/extract_pdf.py" \
"<PDF路径>" --output-dir "<输出目录>" \
[--dpi 200] [--no-images] [--no-tables] [--no-links]
> Windows 上若 python3 不存在,改用 python。脚本不依赖任何客户端专属运行时。
参数说明:
--dpi:扫描/乱码页渲染分辨率(默认 200)--no-images/--no-tables/--no-links:分别关闭图片 / 表格 / 超链接提取
3. 解析 JSON 结果
脚本只向 stdout 输出 JSON,诊断信息写 stderr(stdout 始终为单个纯净 JSON 对象)。
结构:
- 成功:
ok=true,含markdown_path、document_info、pages、summary document_info.outline:文档大纲(TOC)列表[层级, 标题, 页码]summary.scan_pages:需要视觉识别的页码列表summary.link_count/table_count/image_count- 每页
text_status:extracted(文字已提取)、scan_required
(已渲染 PNG 待视觉识别)或error(该页处理异常,见warnings) - 每页
warnings:如garbled_text_detected(文字层疑似乱码) - 每页
images[].bbox:图片在页面中的坐标{x0,y0,x1,y1} - 每页
links:超链接列表[{kind, uri?, page?}] - 失败:
ok=false,含error.code,可能为
FILE_NOT_FOUND/NOT_PDF/OPEN_FAILED/PASSWORD_REQUIRED/
WRITE_FAILED/UNEXPECTED_ERROR/IMPORT_FAILED
4. 扫描页视觉回填(关键)
若 summary.scan_pages 非空:
- 对列表中每一页,读取对应 PNG:
扫描目录/pNNN.png - 使用视觉能力识别其中文字、标题、表格,如实回填到 Markdown 的
<!-- page:N -->区块 - 无法确认的内容标注“[识别不清]”,不得臆造
- 完成后在对话摘要中说明哪些页来自视觉识别
5. 交付
- 默认交付:
<输出目录>/<原文件名>.md文件 + 对话内摘要 - 摘要应包含:源文件、页数、文字页/扫描页、表格数、图片数、任何警告
- 图片/表格/扫描图位于同目录
images\、tables\、scans\,Markdown 用相对路径引用
输出目录结构
<原文件名>_extracted\
├── <原文件名>.md (正文 + 表格 + 图片引用)
├── images\ (按内容去重后的嵌入图片;已过滤整页背景/横幅/纯色块)
├── tables\ (每张表一个 UTF-8-SIG CSV)
├── tables_preview\ (表格区域裁切 PNG,供核对版式)
└── scans\ (疑似扫描页/乱码页的 PNG,供视觉识别)
注意事项
- 隐私:文件仅在本次提取中使用,不主动上传或存储到外部。
- 图片内容级过滤:除尺寸过滤外,自动跳过①整页背景图(覆盖页面面积 ≥ 85%)②极端宽高比
(长边/短边 ≥ 12,疑似横幅/分隔条)③大面积纯色块。目的:去掉水印/logo/背景噪声,
保留真实前景图(晶体等产品图不受影响,因其面积小)。 - 乱码页判定:当文字层出现 U+FFFD 替换符、或 Latin-1 mojibake 双字符(如
é代é)、
或 CJK 乱码特征(大量 Latin-1 组合符且无真实 CJK)时,判为乱码页并渲染 PNG 交视觉识别,
不再吐垃圾文字。此举直击“可变字体导出复制乱码”的真实坑。 - 扫描/乱码识别:视觉识别依赖图像清晰度,模糊页可能不完整;结果应声明“已尽力按视觉结构整理”。
- 复杂版式:跨页表、嵌套表、极其不规则排版可能提取不佳,属已知限制。
- 文件大小:建议 < 100MB;超大文件逐页处理,耗时较长。
- 加密 PDF:需用户提供密码;脚本会返回
PASSWORD_REQUIRED,不尝试破解。
使用示例
用户:提取这个 PDF 的文字和表格 → C:\data\catalog.pdf
处理:
1. 运行脚本,--output-dir C:\data\catalog_extracted
2. 读取 JSON:10 页,其中第 3、7 页 scan_required
3. 读取 scans/p003.png、scans/p007.png 视觉识别并回填
4. 交付 catalog_extracted\catalog.md 与摘要