美文网首页
开发日记pdf扫描版提取

开发日记pdf扫描版提取

作者: 宴会说 | 来源:发表于2025-10-16 18:20 被阅读0次

2025年10月17日,星期五,凌晨 00:03

我把 27 寸显示器的亮度调到最低,还是晃眼。不是因为灯,是因为脑子里那行红字在闪:

“扫描版 PDF 无法解析,chunk 为空,检索返回 None。” 

昨天老板把需求钉死在飞书日历里——“明天上线,能回答 2019 年那份 800 页纸质合同里的任意条款”。那份文件只有扫描版,连目录都是手写。我原本的计划是:pdfplumber → 分句 → 向量化 → FAISS → 收工。结果第一行代码就报错:

`PDFTextExtractionNotAllowed` 

00:17

Google 说这是“all-text”标记为 False 的典型扫描件。我骂了自己一句“眼瞎”,怎么没先跑一遍 `pdfinfo`。于是转向方案二:先整本转图片,再 OCR。这样还能顺带把印章、手写批注也收进来,老板以后问“乙方盖章没”也能答。 

00:46

选工具时我没人可问,只能让 Cursor 里的 GPT-4o 列清单:pdf2image、poppler、pytesseract、PaddleOCR、easyocr……我挑了 pdf2image,因为名字最短。pip  install 后,第一次 `convert_from_path` 就抛:

`pdf2image.exceptions.PDFInfoNotInstalledError: Unable to get page count. Is poppler installed and in PATH?` 

我这才想起 pdf2image 只是 Python 壳,真干活的是 poppler-utils。可我是 M2 芯片的 macOS,brew install poppler 居然要 17 个依赖,其中 glib 还链到 cairo,链到 pixman,链到一堆我没听说过的古老家族。更惨的是,公司笔记本没给管理员密码,/usr/local 写不进去。 

01:35

只能把 poppler 装到用户目录:

`./configure --prefix=$HOME/.local`

`make -j8 && make install`

再把 `$HOME/.local/bin` 写进 PATH。make 跑到 87% 时报“undefined symbol  cairo_tag_end”,我差点把键盘掀了。StackExchange 说降级 cairo 1.16.0 可解,于是卸载重装,来回又 20 分钟。 

02:11

poppler 总算过,pdf2image 能吐出 PNG 了。我写了 4 行脚本,把 800 页一口气拆成 800 张 300 DPI 彩图,文件夹瞬间 3.2 GB。我没在意,先睡了。 

07:20

被闹钟拽醒,第一反应是跑 pytesseract。结果 10 分钟只跑了 12 页,终端里全是 Warning: Invalid resolution 0 dpi. Using 70  instead. 我意识到 300 DPI 对 tesseract 太重,而且单线程。于是把 DPI 降到 150,再写 multiprocessing.Pool(8),速度×6,可准确率掉到 72%,大片“一”被识别成“——”,数字 0 和 O 混成一团。 

09:03

我让 Cursor 生成 20 条测试 QA,检索精度只有 41%,完全不能用。想上 PaddleOCR,但 M2 版 torch 1.13 与 paddle 2.5 冲突,pip 解了半小时依赖,最终放弃。 

09:47

决定呼叫“钞能力”——商业 OCR。挑了某云,每月送 1000 次免费,超出 0.015 元/次。800 页刚好 800 次,还能留 200 次给老板二次上传。写了个脚本: 

1. 把 150 DPI 图批量 base64 

2. async aiohttp,限并发 10 

3. 失败自动退避重试 

4. 返回直接给 UTF-8,不再走 tesseract 

11:12

接口 15 分钟跑完,花 12 元。我顺手把结果写进 SQLite,字段:page_id, bbox, text, confidence。平均置信 96%,比本地高 24 个点。检索测试拉到 87%,终于像个人样。 

11:30

准备收工时,发现 pdf2image 转图这一步居然占总耗时 70%。150 DPI 仍要 4 秒/页,800 页≈1 小时。老板可不会等。我把 DPI 再降到 72,页均 1.1 秒,可文字糊成一团,OCR 置信掉到 88%。权衡后折中:正文页 100 DPI,附表页 150 DPI,写了个规则引擎,把带“表格”“附表”字样的页自动调高。 

12:05

并行化继续加码。pdf2image 本身没暴露并发参数,我只能把 800 页拆 8 组,开 8 进程同时调 convert_from_path,每组 100 页。没想到 poppler 内部用到了全局锁,8 进程只比 1 进程快 30%。StackOverflow 说可以换 pdftocairo,加 `-singlefile` 参数,锁粒度更细。我重写了底层,再把进程提到 16,总耗时从 58 分钟压到 19 分钟,CPU 96 ℃,风扇像直升机。 

13:40

所有图片、OCR、向量化跑完,我打包成 Docker 镜像,塞进 8 核 16 G 的测试机。端到端跑一遍:

上传 PDF → 转图 → OCR → 分句 → embedding → FAISS → 检索 → 大模型生成答案

总耗时 22 分 17 秒,单次问答 1.4 秒,成本 12 块 8 毛。 

14:00

我把结果甩给飞书机器人,让它随机问:

“合同里乙方违约金比例是多少?”

“扫描件第 517 页骑缝章是否完整?”

“附件三的技术指标表格里,延迟上限写多少毫秒?”

十条全对,机器人回了三个。 

14:15

我在日记里写下最后的备注: 

1. pdf2image 只是壳,真正的敌人是系统级依赖;CI 里一定加 poppler 缓存。 

2. DPI 不是越高越好,100-150 区间性价比最佳,表格页可动态调。 

3. 本地 OCR 救不了中文扫描,该花钱就花钱,12 块买我 8 小时,值。 

4. 并行要小心 C 扩展的全局锁,pdftocairo 比 pdftoppm 更适合多进程。 

5. 一切折腾完,记得把风扇清灰,CPU  thermal throttle 会让提速一夜回到解放前。 

14:30

关掉显示器,阳台外太阳正好。我盯着手机上的成本清单:

poppler 编译 0 元,电费约 1.5 元,OCR 12.8 元,总计 14.3 元。

换我一天不眠不休,终于把“无法解析”四个字变成了“87% 召回”。

RAG 的 R,今天算是踩实了。

相关文章

网友评论

      本文标题:开发日记pdf扫描版提取

      本文链接:https://www.haomeiwen.com/subject/zpdotstx.html