文档分类、阅读顺序与PDF
数字PDF可能包含文本对象,扫描PDF可能只有页面图像,混合PDF可能两者都有。文件能选中文字不等于顺序正确:绘制顺序、视觉阅读顺序、语义结构是三件事。先检查页面是否有可用文本层,再决定直接提取、OCR或版面识别。
下面模拟一页双栏的文本块。每个块含左上角坐标,y向下增加,单位统一。按y排序会把左右栏交替拼接;确认确实双栏之后,才可先列后行。
python
blocks = [
{'x': 20, 'y':20, 'text':'左栏第一段'},
{'x':300, 'y':20, 'text':'右栏第一段'},
{'x':20, 'y':70, 'text':'左栏第二段'},
{'x':300, 'y':70, 'text':'右栏第二段'},
]
row_order = sorted(blocks, key=lambda b:(b['y'],b['x']))
col_order = sorted(blocks, key=lambda b:(b['x']>=200,b['y']))
assert [b['text'] for b in row_order] == ['左栏第一段','右栏第一段','左栏第二段','右栏第二段']
assert [b['text'] for b in col_order] == ['左栏第一段','左栏第二段','右栏第一段','右栏第二段']
print([b['text'] for b in col_order])这不是通用PDF解析器:跨栏标题、脚注、旋转页会破坏固定阈值。生产中保留原块、bbox、页码、解析器版本、阅读顺序关系,再转换为段落树。删除重复页眉应依据跨页位置与重复性,不能全局删掉某行文字,因为正文可能引用同一句。
解析成功如何检查
先抽取少量代表页,与原图逐块核对:字符是否丢失、段落顺序是否错、表格行列是否串、脚注是否挂对。文本覆盖率、空页率、乱码比例可作为警报,但不是正确性评分。中文字体映射丢失时有文字对象也可能解码乱码,需要OCR备用而非重复拼接两份文本。
将文件转换为中间结构:Document→Page→Block→Span,表格和图片保留独立节点;后续切分在结构上执行。原始字节只读归档,规范化文本另存。不可逆删除后就无法核对错误引用。异常页单独标记需复核,不把整份文件静默当作成功。
HTML、Markdown、DOCX本来有标题层级,应优先读取结构;纯文本没有结构时才尝试启发式。PDF分页是表现单位,不一定是语义段落边界,因此不能把“每页一片”当作普遍答案。
练习
在上例加一条跨栏标题x=20,y=0。先把它识别为标题,再按列排序剩余正文,要求标题仅出现一次。
完成后查看本章答案。
下一篇:继续本章完整实验。