使用PyMuPDF提取PDF文本时,文本提取顺序与视觉布局不符(坐标正确但逻辑顺序错误)
使用PyMuPDF提取PDF文本时,文本提取顺序与视觉布局不符(坐标正确但逻辑顺序错误)
我完全懂你碰到的这个糟心问题!复杂布局的PDF(比如多栏排版、混着表格的文档)经常会出现这种情况——PyMuPDF默认是跟着PDF内部的文本绘制顺序来提取内容的,但这个顺序和我们视觉上的阅读顺序往往完全不搭,哪怕每个文本块的坐标都是准确的。你之前试过的普通按x/y坐标排序之所以没起作用,是因为它太“一刀切”了,没考虑到多栏布局的栏边界,也没区分表格这类特殊元素的内部逻辑。
下面给你几个针对性的解决思路和实操方案:
核心思路:放弃默认顺序,基于坐标做精细化的文本块分组排序
既然PDF内部的文本顺序本身就有问题,我们就直接跳过它,把所有文本块拆成最小单元,然后模拟人类的阅读逻辑(先左栏后右栏,先上后下,表格按行/列顺序)来重新排序。
步骤1:获取结构化的文本块数据
先用PyMuPDF的page.get_text("dict")获取带坐标的结构化文本,而不是直接取纯文本。这个接口会返回每个文本块的边界框(bbox)、行、字符跨度等信息,方便我们后续处理:
import fitz # PyMuPDF doc = fitz.open("你的PDF文件路径.pdf") page = doc[0] # 取第一页示例 text_struct = page.get_text("dict") # 过滤掉非文本块(比如图片、图形) text_blocks = [block for block in text_struct["blocks"] if block["type"] == 0]
步骤2:针对多栏布局的排序方案
如果你的文档是多栏排版,首先要把文本块按“栏”分组,再在每栏内部按垂直顺序排序,最后按栏的顺序拼接:
def sort_multi_column_blocks(page, text_blocks): page_width = page.rect.width # 这里假设是两栏,可根据实际情况调整,也可以自动聚类x坐标来检测栏数 column_gap = 50 # 栏之间的间距,可根据你的文档调整 column_width = (page_width - column_gap) / 2 # 按栏分组 left_column = [] right_column = [] for block in text_blocks: bbox = block["bbox"] # 用文本块的中心x坐标判断属于哪一栏 block_center_x = (bbox[0] + bbox[2]) / 2 if block_center_x < column_width: left_column.append(block) else: right_column.append(block) # 排序规则:先按顶部y坐标(越靠上越先),再按左侧x坐标(越靠左越先) def block_sort_key(block): return (block["bbox"][1], block["bbox"][0]) left_column.sort(key=block_sort_key) right_column.sort(key=block_sort_key) # 拼接文本:先左栏后右栏 sorted_text = "" for block in left_column + right_column: for line in block["lines"]: for span in line["spans"]: sorted_text += span["text"] + " " sorted_text += "\n" return sorted_text # 使用示例 sorted_result = sort_multi_column_blocks(page, text_blocks) print(sorted_result)
步骤3:针对表格的特殊处理
如果文档里有表格,你可以先用PyMuPDF的page.find_tables()识别表格区域,然后单独对表格内的文本块按行/列排序:
def sort_table_blocks(table): # 从表格对象中提取单元格文本,按行优先排序 sorted_table_text = "" for row in table.rows: row_text = "\t".join([cell.get_text().strip() for cell in row.cells]) sorted_table_text += row_text + "\n" return sorted_table_text # 识别页面中的表格 tables = page.find_tables() for table in tables: table_text = sort_table_blocks(table) # 可以把表格文本替换到排序后的整体文本中,或者单独处理
额外小技巧
如果你不想自己写复杂的排序逻辑,也可以试试PyMuPDF的page.get_text("text", sort=True)参数,但这个参数只是简单按x/y坐标排序,对多栏、表格这类复杂布局的支持有限,还是自定义排序更靠谱。
备注:内容来源于stack exchange,提问作者Phalgun
相关产品推荐
相关产品推荐

