PDF 解析

先分流,再 OCR:用 PyMuPDF 给每一页留一个可复核的判断

同一份 PDF 可能混有文本页、扫描页和空白页。用三个合成页面验证分流逻辑,解释为什么“能抽到字”仍不等于内容完整。

阅读文本 / Reading text
先分流,再 OCR:用 PyMuPDF 给每一页留一个可复核的判断 收到一份几十页的 PDF,第一反应常常是“整本跑一遍 OCR”。这很省思考,却把三种完全不同的页面交给了同一种处理方式:本来就有文本层的页、只有扫描图像的页,以及没有正文的页。更麻烦的是,三种页面可能同时出现在一个文件里。本文先做一件小事:为每页记录处理路线和判断依据,给后续提取、翻译、复核留下入口。 把结论写成“候选”,而不是“已经识别正确” 下面的规则刻意保守。有可提取文本,标为文本候选;没有文本但显示了图像,标为 OCR 候选;两者都没有,进入复核。这不是扫描件分类器,更不是识别质量评分。比如一张只有页码的扫描页也会进入文本候选,所以记录路线之后还必须看缩略图,不能把这个标签当成全页内容已提取的证明。 这一页该走哪条路? 可点击的教学示例;不上传文档,不调用接口。 全屏 图 1 可切换的判断示意。仅演示处理规则,不代表产品界面或真实效果。 表 1 分流信号与容易误判的情况 观察 路线 不能据此认定 抽到非空文本 文本候选 文本层正确、顺序正确或覆盖全页 无文本,有显示图像 OCR 候选 图像一定含文字 无文本,无显示图像 复核 这一页一定可删除 用三页合成样本跑出一个确定结果 示例在内存中创建英文文本页,把它渲染成图片后插入第二页,最后加一张空白页。它不读取客户文件,也不依赖识别服务。安装 PyMuPDF 后保存代码为 page_routes.py,再运行 python page_routes.py。下列连续代码段应按顺序复制到同一文件。 import pymupdf def inspect(page): text = page.get_text("text").strip() images = page.get_image_info() if text: route = "text_candidate" elif images: route = "ocr_candidate" else: route = "review_empty_or_vector" return {"page": page.number + 1, "route": route, "characters": len(text), "images": len(images)} # Synthetic fixtures, not customer files. with pymupdf.open() as source: p = source.new_page(width=300, height=160) p.insert_text((20, 60), "Invoice DEMO 1200.50") png = p.get_pixmap(dpi=120, alpha=False).tobytes("png") with pymupdf.open() as doc: doc.insert_pdf(source) p = doc.new_page(width=300, height=160) p.insert_image(p.rect, stream=png) doc.new_page(width=300, height=160) rows = [inspect(p) for p in doc] assert [r["route"] for r in rows] == [ "text_candidate", "ocr_candidate", "review_empty_or_vector"] assert rows[0]["characters"] > 0 assert rows[1]["characters"] == 0 assert rows[1]["images"] == 1 for row in rows: print(row["page"], row["route"]) 本机在 Python 3.13.11、PyMuPDF 1.28.0 上执行得到:第 1 页 text_candidate,第 2 页 ocr_candidate,第 3 页 review_empty_or_vector。断言同时检查了第二页抽不到文本但确实显示一张图像。这只验证分流程序在这三个可控样本上的行为;本文没有运行 Tesseract,也没有给出真实扫描件的识别准确率。 接入 OCR 时最容易漏掉的一步 PyMuPDF 的 OCR 接口依赖额外安装的 Tesseract 及对应语言数据。拿到 OCR TextPage 后,后续提取要明确传入 textpage;再次直接对原页抽取文本,并不会自动使用刚才的识别结果。官方文档给出的复用模式如下。此片段未在本次实验中执行,需先安装语言数据。 # page 必须仍属于一个打开的 Document tp = page.get_textpage_ocr(language="eng", dpi=200, full=True) text = page.get_text("text", textpage=tp) full=True 的完整页识别不是对所有文件都最合适。混合页需要决定保留已有文本还是重新识别;不同版本对部分 OCR 的行为也可能变化,应锁定依赖版本再做回归。不要用一个 OCR 结果覆盖原始文本字段,建议分别保留 raw_text、ocr_text、engine_version、language 和人工选择结果。页面旋转、中文语言包、印章与小字号都要有独立样本。 交付前验收的是证据链 至少保存文件摘要、页号、抽取路线和失败原因,并抽查文本在原页上的位置。把金额、表格与关键条款单独复核,不用“字符数很多”代替准确性。对于无文本的页面,既不要直接删除,也不要静默写入空字符串后宣告成功。 如果你在 OmniDoc 中组织文档处理与翻译工作,可以把这张分流清单作为输入检查附件:保留原稿,让处理结果有页号可追溯,再进入后续翻译和交付。这里演示的是独立的开源代码流程,不是对 OmniDoc 内部识别算法或效果的承诺。 参考与产品入口 PyMuPDF:OCR 操作指南 PyMuPDF:Page API OmniDoc 产品入口 - 1 -
更新于 2026-10-10