扫描件 PDF:先判断有没有文字层,再修
十秒分辨扫描件还是文本件,工具为什么用 PDF_NO_TEXT_LAYER 直接拒绝,怎么在不把页面送出去的前提下做 OCR,以及识别错误如何变成检索错误。
· 8 分钟阅读
扫描件 PDF 是页面的一张图,而文本提取器只能返回页面上真实存在的字符,问题就出在这里:文件看起来是文档,打开也像文档,里面却一个字都没有。下面讲怎么用十秒确认这一点、怎么在不把页面送出去的前提下做识别,以及识别错误之后对检索造成的影响。
十秒判断扫描件还是文本件
第一种办法不需要任何额外工具。用你手上的阅读器打开 PDF,在页面中间挑一段普通正文,用鼠标去选。文本件会高亮出文字,也能复制;扫描件什么都不会高亮,或者一拖就拽出一个整页大小的框,像抓住了一张图片。
第二种办法是工具自己的回答。把文件拖进去看状态:扫描件会被拒绝并报出 PDF_NO_TEXT_LAYER,提示里写明未检测到文字层。这个错误码是专用的——它和加密文件的 PDF_ENCRYPTED 不同,也和超大文件的 FILE_TOO_LARGE 不同。
| 你看到的 | 说明什么 | 接下来怎么做 |
|---|---|---|
| 任何阅读器里都能选中并复制文字 | 文件有真正的文字层 | 直接导入,下面都不用看 |
| 选不中,但页面清晰、字型规整 | 电子生成的扫描件,多半是从排版稿渲染的 | 做 OCR,导入识别结果 |
| 页面是纸的照片,有倾斜和阴影 | 相机或平板扫描仪拍的 | 做 OCR,导入前先核对 |
导入报 PDF_NO_TEXT_LAYER |
解析器在整份文件里读到零个字符 | 先 OCR,再导文本 |
导入报 PDF_ENCRYPTED |
设置了密码或所有者限制 | 在生成它的工具里去掉保护,再导入解密后的副本 |
还有一种混合文件:报告正文是文字层,附件是扫描页。解析器会把它能取的取出来,结果就是索引里只有正文,附件是空的。在断定某条款不存在之前,这一点值得先确认。
工具为什么直接拒绝,而不是塞个空壳
技术上当然可以接受扫描件、然后索引一个占位符,或者只把文件名和页数写进去。这样做的结果是得到一个看起来健康、实际什么都答不出来的索引。一个明确的错误比一个沉默的空文档有用,所以解析器抛出错误码并把原因写在提示里。
隐私上也有一条理由,让这个决定保持显式。扫描件里敏感材料的比例偏高:签了字的合同、证件页、体检表、银行流水。恰恰是这类材料,先上传的工作流代价最大;也恰恰是这类材料,一个挡住导入的错误帮了你一把。
在不把页面送出去的前提下做 OCR
原则很简单:识别应该发生在图像已经在的地方。三种安排里只有一种是远程的。
- 在浏览器里识别。 一部分扫描软件和文档工具自带在页面内运行的识别引擎,不往外发任何东西。
- 在你自己的电脑上识别。 桌面版 OCR 程序,或者装在机器上的命令行识别工具,用你自己的处理器处理页面,输出一个文本文件,再导进来。
- 在别人的电脑上识别。 云端 OCR 服务接收图像并返回文字。页面图像在进去的路上就离开了你的设备,之后怎么留存由服务方的规则决定。
只有前两种让材料留在本地。用第三种的话,如实地说,这个扫描件已经披露给了另一个主体;后续的导入虽然发生在本地,但整个故事已经不完整了。凡是有签署、有账号、有保密条款的内容,请走前两条路,接受多花的那几分钟。
具体该用哪个本地识别工具,本文给不了承诺,因为这个领域的工具变化很快,我们也没有逐一测试过。选择时优先考虑安装后可以完全离线运行的,并且用你验证本站的同一个办法去验证它:断网看它还能不能干活。
把识别出来的文本导回来
拿到文本之后,导入路径和任何纯文本文件一样,这一步的几个选择会在后面省事。
- 保留页码标记。 识别工具如果能在每页开头插入页码或分页标记,就留着。带页码的文本块元信息能让引用指回你可以用眼睛核对的那一页。
- 导文本或 Markdown,别导重新包好的 PDF。 识别生成的可搜索 PDF 只多了一个容器,没有增加可检索内容,还要占用单文件和总量额度。
- 有标题就把标题恢复出来。 识别成的一行标题,如果不标成 Markdown 标题,就只是普通句子。恢复标题层级等于给切分器真实边界,差别是干净的一块和从上一节中间开始的一块。
- 按文档分,不要按文件夹分。 限额针对单个文件和整个库,所以一份 60 页扫描件导成一个文本文件,比拆成四十个单页文件更好管理。
- 去掉重复的版面元素。 识别工具经常把页脚变成每一页都出现的同一行文字。导入前删掉这些重复行,能改善关键词检索,原理和清洗器去掉电子 PDF 的重复页眉一样。
OCR 的错误会变成检索的错误
这一段值得读两遍。电子 PDF 里,错字根本进不了索引。扫描件里,识别结果决定了索引的内容,错误造成的差异是永久的——文档写的是什么和检索能搜到什么,从此对不上。
具体一点:如果识别引擎把保单号里的 0 认成 O,把编码里的 1 认成 l,或者把表格的两栏读成交错的行,那么按正确写法去搜,那一段就是搜不到。混合检索里负责救回精确标识的正是关键词那一半,而识别错误恰恰是它的克星。向量那一半也帮不上,稠密向量会把稀有词模糊掉,不会把它还原出来。
| 识别失败 | 对结果的影响 | 在哪里能发现 |
|---|---|---|
| 编号里数字与字母混淆 | 精确检索落空,只剩模糊的相关度排序在起作用 | 导入后立刻搜一次这个编号 |
| 双栏版面被读成交错行 | 句子变成词串,段落进了索引但读不成句 | 读一遍导入文本的第一页 |
| 表格整行被压成一行 | 列值和行标签的对应关系丢失 | 打开有表格的那一页看文本 |
| 变音符号或非拉丁文字被丢弃 | 词变成别的词,关键词检索失效 | 搜一个你在扫描件里看得见的普通词 |
| 阴影导致整块区域被识别成噪声 | 内容从索引里彻底缺失 | 对比识别文本的页数与扫描件的页数 |
导入后花两分钟自查能拦住大部分问题:打开你刚导进去的那个文本文件,对照扫描件读一遍第一页,再用你从原件上能读到的某个编号或名称,在工具里做一次精确检索。两项都过了,后面通常也在同一水平。
这些事它做不到
扫描件里本来就没有的内容,OCR 变不出来。模糊的一页、盖在签名线上的印章、页边的手写批注,识别结果往往是看似肯定的错误文本,或者干脆是空的。如果你的问题取决于一处手写标注,这份扫描件是搜不到的,只能由人去看图像。
还有一点要说清楚:这个工具不做 OCR。它解析你文件里已经存在的文本,而扫描件里没有文本。修这件事的环节在更上游,由你选择和掌控,那一步的质量决定了后面检索能力的上限。