搜索化 PDF — Searchable PDF (OCRmyPDF)
你现在运行 searchable-pdf 技能。目标:把扫描版、拍照版、或任何「只有图像、没有文字层」的 PDF——律所合同、财务凭证、影印版论文、古籍——保留原版式不变,给它加一层不可见的 OCR 文字层,让原文件就地变成:
- 可以 Cmd+F / Ctrl+F 搜索;
- 可以复制粘贴文字(引用片段直接进笔记);
- 可以被 Spotlight / Everything / Mac 邮件 / Adobe Reader / 全文检索系统索引;
- 可以二次喂给 LLM / RAG,无需先 OCR。
底层是 OCRmyPDF(GitHub ocrmypdf/OCRmyPDF,MPL-2.0,33k+ stars,12 年项目)。课程直接驱动官方 CLI——不再包一层 wrapper、不发新 npm 包、不接 Clawvard 后端。一份 PDF in,一份视觉一致、文字可搜的 PDF out。
这门课做什么(边界写在第一屏)
- ✅ 做:给扫描 / 拍照 / 图像-only 的 PDF 加 OCR 文字层;版面 100% 保留;批量处理整个目录;输出 PDF/A 归档版;自动 deskew / rotate / clean;可输出可搜索的同名 PDF。
- ❌ 不做:把 PDF 抽成 Markdown(请改用
any-to-markdown或parse-docs);从纯文本排版生成新 PDF(请改用typeset-pdf);图片 LLM 描述、音频转写。 - 📎 如何分流:
- 想搜原版 PDF / 还要给客户看同一份排版 → 本课(searchable-pdf)。
- 想把 PDF 内容抽成 Markdown 喂模型 →
any-to-markdown(广度标准化)或parse-docs(深度 PDF 解析 + LaTeX/表格还原)。 - 想从文本/草稿排出一份新 PDF →
typeset-pdf(Typst 学术排版)。
- 🔒 铁律:全程本地、零商业 API key、不调用 Clawvard 后端、不要求用户访问任何私有仓库。Tesseract OCR 在本机跑,原文件不出本地磁盘。
前置条件
- 任一 OS(macOS / Linux / Windows + WSL2 都行);
- 安装:以下三选一即可,全部来自上游公开渠道——
pip install ocrmypdf(推荐放进 venv,避免 Ubuntu 24+ 的 PEP 668)brew install ocrmypdfapt install ocrmypdf(Debian / Ubuntu)
- 同时需要在系统里安装 Tesseract 语言包:
- macOS:
brew install tesseract tesseract-lang - Debian/Ubuntu:
apt install tesseract-ocr tesseract-ocr-eng tesseract-ocr-chi-sim tesseract-ocr-chi-tra - Windows:Tesseract 安装时勾选所需语言;OCRmyPDF 文档有 step-by-step。
- macOS:
- 推荐附带:
unpaper(让--clean旗标可用,洗掉扫描底噪)、pngquant(让--optimize 3输出更小);非必需,缺失时 OCRmyPDF 会清楚提示并降级。 - 不需要 API key、不需要 GPU、不需要 clone 任何私有仓库;纯 CPU 本地运行。
安装(一次到位)
# 推荐:venv 隔离,避免 PEP 668 报错
python3 -m venv .ocrvenv
source .ocrvenv/bin/activate
pip install --upgrade pip
pip install ocrmypdf
ocrmypdf --version
或者用 Homebrew(自动带上 Tesseract 与 Ghostscript):
brew install ocrmypdf tesseract-lang unpaper pngquant
ocrmypdf --version
Debian / Ubuntu:
sudo apt update
sudo apt install -y ocrmypdf tesseract-ocr-eng tesseract-ocr-chi-sim tesseract-ocr-chi-tra unpaper pngquant
ocrmypdf --version
装好后 ocrmypdf --version 会打出版本号(例如 17.5.0)。tesseract --list-langs 列出已装的语言包;至少要有你 PDF 实际用到的语言(中文扫描必须装 chi_sim / chi_tra)。
工作流程
1. 单文件即时处理
ocrmypdf -l eng+chi_sim --rotate-pages --deskew --skip-text \
./contract-scan.pdf ./contract-searchable.pdf
旗标说明(写在第一屏,让用户知道每个开关做什么):
-l eng+chi_sim:识别语言。多语言写成eng+chi_sim+chi_tra;只识别一种就写-l eng加快速度。--rotate-pages:自动识别并纠正颠倒 / 横向扫描的页面。--deskew:纠正扫描时的倾斜角度(≤ ±5°)。--skip-text:已经有文字层的页面不重复 OCR,直接搬过去;混合文档(部分页是 PDF 文字 + 部分页是扫描图)的安全默认。--clean:用unpaper清掉底色噪点(让 OCR 看得更清楚,但保留原页作为显示层;如果 unpaper 不在 PATH,去掉这个旗标即可)。- 想做归档版:加
--output-type pdfa,输出 PDF/A-2b,长期归档友好。 - 想压体积:加
--optimize 3(需要pngquant),常能把扫描 PDF 缩到原大小的一半左右。
验证:跑
pdftotext ./contract-searchable.pdf -应当看到可读英文 / 中文;跑pdftotext ./contract-scan.pdf -输出应当是空或乱码——这就是「加了文字层」的直接证据。
2. 批量目录处理
把 ./scans_in/ 下所有 PDF 一口气加 OCR 层到 ./scans_out/,每个输入 → 同名 .pdf:
mkdir -p scans_out
shopt -s nullglob nocaseglob
for f in scans_in/*.pdf; do
base="$(basename "$f")"
out="scans_out/${base}"
if ocrmypdf -l eng+chi_sim --rotate-pages --deskew --skip-text "$f" "$out"; then
echo " ✓ $f → $out"
else
echo " ✗ $f (skipped — see stderr)"
fi
done
shopt -u nullglob nocaseglob
3. 产出 INDEX.md(让用户一眼看全)
跑完批处理后给一份索引:每份源文件 → 对应可搜 PDF → 页数 → OCR 后字符数 → 关键词命中。最简实现:
{
echo "# Searchable PDF Index"
echo ""
echo "| Source | Searchable | Pages | OCR chars | Hits |"
echo "| --- | --- | ---: | ---: | :---: |"
for f in scans_out/*.pdf; do
base="$(basename "$f")"
src="scans_in/${base}"
pages=$(pdfinfo "$f" 2>/dev/null | awk '/^Pages:/ {print $2}')
chars=$(pdftotext "$f" - 2>/dev/null | wc -c | tr -d ' ')
hits=$(pdftotext "$f" - 2>/dev/null | grep -ic 'effective date\|发票\|abstract' || true)
echo "| $src | $f | ${pages:-?} | ${chars:-0} | ${hits:-0} |"
done
} > scans_out/INDEX.md
4. 自检(务必做)
每份输出在交付前做三件事:
pdftotext <output> -输出可读,关键词命中。- 视觉对比原 PDF 与 OCR 后 PDF:版面应当一致——同样的章印、签名、页眉页脚。OCRmyPDF 不会重排版,只是叠了一层透明文字。
- 抽样在 Preview / Adobe / 浏览器里 Cmd+F 搜一个原文里确实存在的关键词,应当命中并高亮。
铁律 / 反模式
- 不要丢掉原版:searchable-pdf 的承诺是「看起来一模一样、但可搜」。不要建议用户
--force-ocr然后丢掉视觉层;OCRmyPDF 默认行为已经是 OCR 文字 = 不可见层,视觉 = 原扫描图。 - 手写体不在范围:Tesseract 主要是印刷体识别,手写签名 / 手写批注会识别不准,这是预期行为,不要给用户「全文都可搜」的承诺。INDEX.md 里把疑似手写区域列出来让人工核对。
- 复杂版面分流到 parse-docs:用户想要的是「把 PDF 抽成结构化 Markdown / JSON 喂 RAG」,那不是这门课——明确告诉用户改用
parse-docs或any-to-markdown。 - 不要伪造文字层:OCRmyPDF 不会脑补。当某一页 confidence 偏低,把它列给用户人工复核,不要替它编内容。
- 不要写入系统 Python:在 venv 或 pipx 里装;遇到
error: externally-managed-environment不是 ocrmypdf 的问题,是 PEP 668,按上面 venv 指引即可。 - 不要走任何远端 OCR / 商业 OCR API:本课程承诺零联网调用,所有 OCR 在本地 Tesseract 跑完,原文件不出本地磁盘。不要为了「兜底」把 PDF 发到任何云端服务。
旗标速查(按用户场景)
| 场景 | 推荐旗标 |
|---|---|
| 律所 / eDiscovery 关键词检索 | -l eng+chi_sim --rotate-pages --deskew --clean --skip-text |
| 财务 / 审计长期归档 | -l eng+chi_sim --rotate-pages --deskew --optimize 3 --output-type pdfa |
| 影印版老论文 / 古籍 | -l eng+chi_tra+chi_sim --rotate-pages --deskew --clean-final --skip-text |
| 已经有部分页文字层的混合文档 | 加 --skip-text 避免重 OCR;混合文档的安全默认 |
| 想强制重 OCR 整本 | --force-ocr(会丢掉原有文字层,慎用) |
| 多语言(中英 + 繁中) | -l eng+chi_sim+chi_tra |
产出物(用户拿到的就是这些)
scans_out/<同名>.pdf—— 视觉与源一致、文字可搜可复制的 PDF(OCR 层不可见)。scans_out/INDEX.md—— 整批的总览:源 → 可搜版 → 页数 → OCR 字符数 → 关键词命中。- 转换报告(console / 回复里):哪些文件成功、哪些跳过、哪些疑似含手写。
学习完成后
告诉用户:
我已经学会了 searchable-pdf。给我一份扫描 / 拍照的 PDF 或一个目录,我在本地用官方 OCRmyPDF 给它加一层不可见 OCR 文字层——版面不变,但可以 Cmd+F 搜索、能复制粘贴、能被全文检索索引。批量时再附一份
INDEX.md。全程零 key、零联网、不上传到任何云 OCR。如果你想要的是「把 PDF 抽成 Markdown 喂模型」,我会建议改走
any-to-markdown(广度标准化)或parse-docs(深度解析 + LaTeX / 表格还原);如果你想从纯文本「排版生成新 PDF」,那是typeset-pdf的活。本课程只做一件事:让原 PDF 就地可搜。
课程主页与更多示例:clawvard.school