智能识别目录怎么生成
打开一份300页的识别生成PDF合同,想找“违约责任”那一条,目录靠肉眼翻页得花两分钟。识别生成如果这份文件有智能识别生成的目录目录,点一下就能跳过去。识别生成这个目录不是目录手动敲出来的,是识别生成程序读出来的。 核心逻辑就一件事:让机器判断哪些行是目录标题,哪些行是识别生成正文。听起来简单,目录做起来全是识别生成细节。 PDF分两种。目录一种是识别生成“真PDF”,文字层完整,目录复制粘贴能出来正常文字。识别生成另一种是扫描件,本质是图片,得先跑OCR。我见过一个项目,开发同学拿到扫描版合同直接调PDF解析库,解析出来全是空白,排查半天才发现文件里根本没有文字层。这一步的坑在于:不判断文件类型就上手写代码,后面全白干。 判断方法不复杂。用PyMuPDF打开文件,调 有了文字层之后,逐行提取文本和格式信息。格式信息包括字号、字体、加粗、颜色、缩进量、行间距。这些东西在PDF里叫“span属性”,PyMuPDF的 为什么格式信息重要?因为人写文档时,标题和正文的视觉差异是刻意做出来的。一级标题通常20号字加粗,正文12号字常规体。机器就靠这些差异做初步筛选。 但光看字号不够。我遇到过一份技术文档,正文里夹了一段14号字的引用,比某些三级标题还大。如果只按字号阈值切,这段引用会被误判成标题。所以得综合判断。 实际操作中,我会给每一行算一个“标题分数”。字号超过正文均值加2分,加粗加2分,独立成行且前后有空行加1分,以数字编号开头(如“1.2”“第三章”)加2分,行长不超过30个字加1分。总分超过阈值就归为标题。 阈值定多少?没有标准答案。我一般先跑一遍,看误判情况再调。合同类文档阈值调低些,因为条款标题往往短且编号规整。学术论文阈值调高些,因为正文里经常出现加粗的关键词。 这套方法跑下来,一份结构清晰的文档,标题识别准确率能到90%以上。剩下的10%怎么办?加一层层级推断。 识别出标题行之后,得知道谁是一级谁是二级。最直接的信号是编号格式:“第一章”肯定比“1.1”高一级,“1.1”比“1.1.1”高一级。编号本身自带层级信息。 没有编号的文档,看缩进。一级标题通常左对齐,二级标题缩进两个字符,三级缩进四个。这个规律在Word导出的PDF里特别明显,因为Word的样式层级会映射成缩进量。 还有一种情况:标题居中。居中且字号最大的,大概率是一级。居中但字号稍小的,可能是二级。这种文档多见于报告和方案。 层级确定后,输出就简单了。构造一个嵌套字典或列表,每个节点包含标题文本、层级、页码。页码从PDF的 写书签用PyPDF2的 有个细节:页码要加1。PDF库的页码从0开始,但阅读器显示从1开始。这个off-by-one我踩过好几次,每次都得重新查。 拿一份50页的技术白皮书测试,手动做目录大概15分钟,程序跑一遍3秒出结果,准确率约92%。错的那8%主要是两种:一是正文里加粗的小标题被漏掉,二是多级列表的编号被误判成标题。 改进方向也有。引入字体名称特征——标题常用黑体或Arial Bold,正文用宋体或Times New Roman。再结合页面布局,标题通常不会出现在页面最底部。这些信号叠加起来,准确率还能再提几个点。 但别指望100%。文档排版千奇百怪,总有人用奇怪的方式做标题。程序能做的就是覆盖大多数情况,剩下的交给人工微调。毕竟生成目录的目的是省时间,不是完全替代人。先搞清楚文件长什么样
page.get_text(),如果返回的字符串长度接近零,基本就是扫描件。这时候得切到OCR流程,Tesseract或者PaddleOCR都行。提取候选行,别急着分类
get_text("dict")能拿到。特征组合比单一规则靠谱
层级关系靠缩进和编号推
生成目录结构
page.number拿。最后序列化成JSON或者直接写进PDF的书签层。addBookmark(),或者PyMuPDF的set_toc()。后者更方便,直接传一个[[层级, 标题, 页码], ...]的列表就行。实际效果和局限