
PDF 表格解析复杂场景知识沉淀适用于政府报告、统计月报、监测数据等结构化 PDF 的自动化提取对上一篇PDF解析知识的拓展一、单元格合并的三种形态合并类型视觉表现PDF 底层真相处理策略行内合并横向一个单元格跨多列该位置只画一次文字无竖线分隔检测列边界缺失将多列内容合并列内合并纵向一个单元格跨多行该位置只在第一行画文字后续行该列为空检测 Y 坐标连续性向下填充直到新记录开始行列交叉合并大块区域合并既无横线也无竖线文字只出现一次结合 X/Y 双向检测标记为合并区域关键难点PDF 没有合并单元格的语义只有某些位置没画文字。程序无法区分是合并还是数据缺失。二、单元格内容多行最隐蔽的问题2.1 视觉表现一个单元格里文字换行了比如┌─────────┐ │ 贵阳市 │ │ 南明区 │ │ 云岩区 │ └─────────┘2.2 PDF 底层实际上是 3 个独立的文字块Y 坐标不同但被框在同一个矩形内。2.3 处理策略第一步先按extract_words提取所有文字块记录每个块的(x0, y0, x1, y1)第二步判断这些块是否属于同一个单元格 —— 看它们的 X 范围是否高度重叠重叠度 80%第三步同一单元格内的多行内容用换行符\n拼接或按业务规则合并如贵阳市\n南明区 → “贵阳市南明区”场景关联水源地名称可能出现原北郊水库\n备用这种多行备注需要识别为同一个单元格。三、跨页表格的处理3.1 跨页的两种模式模式特征处理策略续表模式第二页有续表或接上页字样有表头检测到续表关键词后将两页数据拼接表头去重无标识续页第二页直接继续数据无表头无标识用记录边界检测序号连续性判断是否为同一表格的延续3.2 跨页后表头的四种情况情况示例处理策略每页都有完整表头第1页有表头第2页也有表头提取时识别表头行去重或跳过仅首页有表头第1页有表头第2页直接是数据用首页表头做列定位后续页直接按坐标对齐续页有特殊表头第2页表头简化为续上表XX月报正则匹配续字跳过该行完全无表头第2页直接是数据无任何标识最困难需要用内容特征推断列语义3.3 跨页数据拼接的关键逻辑defmerge_cross_page_tables(pages_data): 跨页表格合并 all_records[]last_seq0forpage_idx,page_recordsinenumerate(pages_data):ifnotpage_records:continue# 检测是否为新表格开始有序号重置first_seqpage_records[0].get(序号)iffirst_seqandfirst_seqlast_seq:# 序号重置 新表格不拼接all_records.extend(page_records)else:# 序号连续 续表拼接all_records.extend(page_records)# 更新最后序号ifpage_records:last_seqpage_records[-1].get(序号,0)returnall_records四、综合处理框架PDF 输入 │ v [Step 1] 逐页提取文字块 (extract_words) │ └── 记录每个词的 (text, x0, y0, x1, y1, page_num) │ v [Step 2] 检测表格区域 │ ├── 有边框 → 用 lines 策略检测单元格边界 │ └── 无边框 → 用文字对齐 空白间隙推断列边界 │ v [Step 3] 单元格重建 │ ├── 单格单词 → 直接赋值 │ ├── 单格多词同行→ X 重叠检测合并为同一单元格 │ ├── 单格多行同列→ Y 连续性检测用 \n 拼接 │ └── 合并单元格 → 标记为 merged向下/向右填充 │ v [Step 4] 记录边界检测 │ ├── 有序号 → 新记录开始最可靠 │ ├── 有城市名 → 新记录开始 │ └── 无标识 → 上一条记录的续行合并到上一条 │ v [Step 5] 跨页处理 │ ├── 检测续表/接上页关键词 │ ├── 检测序号连续性1,2,3... 不中断 │ └── 拼接数据去除重复表头 │ v [Step 6] 后处理 ├── 合并单元格内容填充向下/向右 ├── 多行内容合并按业务规则 └── 输出结构化数据五、关键代码片段5.1 检测单元格内多行内容defgroup_words_into_cells(words,col_boundaries): 将文字块按单元格分组处理多行内容 cells{}forwordinwords:# 找到该词属于哪一列col_idxfind_column(word[x0],col_boundaries)# 找到该词属于哪一行用锚点对齐非简单Y聚类row_keyfind_row_anchor(word,words)key(row_key,col_idx)ifkeynotincells:cells[key][]cells[key].append(word)# 同一单元格内的词按 Y 排序拼接result{}for(row,col),word_listincells.items():word_list.sort(keylambdaw:w[top])text\n.join([w[text]forwinword_list])result[(row,col)]textreturnresult5.2 合并单元格检测与填充defdetect_and_fill_merged_cells(table_data): 检测合并单元格并填充 # 向下填充列合并forcolinrange(len(table_data[0])):last_valueNoneforrowinrange(len(table_data)):iftable_data[row][col]:last_valuetable_data[row][col]eliflast_value:# 当前为空且上方有值 → 可能是合并单元格table_data[row][col]last_value# 向右填充行合并—— 视业务需要# ...returntable_data5.3 跨页连续性检测defis_continuation_page(current_page,next_page): 判断下一页是否是当前表格的续页 # 方法1检测序号连续性current_last_seqget_last_sequence(current_page)next_first_seqget_first_sequence(next_page)ifnext_first_seqandcurrent_last_seq:returnnext_first_seqcurrent_last_seq1# 方法2检测续关键词next_headerextract_header(next_page)if续innext_headeror接上页innext_header:returnTrue# 方法3列数一致且格式相似returnlen(current_page[0])len(next_page[0])六、校验清单处理复杂场景后必须检查校验项方法失败处理序号连续性set(range(1, n1)) - set(实际序号)标记缺失行人工复核城市名不重复同一行同一记录中城市名只出现一次检测合并单元格是否未填充列数一致性所有记录列数相同标记异常行检查多行内容拆分跨页后记录数总记录数 各页之和 - 表头行数检查表头去重逻辑合并单元格填充随机抽样检查填充值是否正确标记异常人工复核七、一句话总结PDF 表格解析的本质是视觉还原工程合并单元格是空值填充多行内容是同格拼接跨页是连续性拼接表头是重复去重。没有魔法只有对坐标、空白、文字的精细工程。