Python提取多表格PDF表格、指定键值对及优化输出格式咨询
现有代码的核心问题
- 未做表格的独立结构化存储,所有表格拼接在同一个CSV文本中,既没有列数对齐处理,也没有空单元格补全逻辑,输出格式混杂。
- Textract调用仅开启了
TABLES特征,缺少FORMS特征支持,无法获取文档内键值对的文本关联关系,无法提取如「Example 1」「Example 2」这类指定键的对应取值。 - 输出逻辑仅支持CSV格式写入,无多工作表写入能力,无法实现多表格拆分存储到Excel的需求。
分模块的改造实现方案
1. 调整Textract调用参数
开启表格+表单双特征提取能力,这是获取键值对关联关系的基础,将原代码中单行的特征参数修改为:
# 原代码为 FeatureTypes=['TABLES'] FeatureTypes=['TABLES', 'FORMS']
修改后,返回的文档blocks集合会同时包含表格结构、表单键值对的关联元数据,不需要自行通过位置猜测文本对应关系。
2. 重构表格结构化解析逻辑
替代原有的CSV字符串拼接逻辑,将每个识别到的表格转换为独立的二维矩阵结构,解决列错位、行顺序混乱的问题:
- 遍历表格所有单元格时,按表格实际的最大列数补全空单元格,避免跨列场景下的列偏移。
- 按行索引、列索引的数值排序,保证表格内容的顺序和PDF中的实际顺序一致。
对应的替换函数示例:
def generate_table_matrix(table_result, blocks_map): rows_dict = get_rows_columns_map(table_result, blocks_map) # 计算当前表格的最大列数 max_col = max([max(cols.keys()) for cols in rows_dict.values()]) table_matrix = [] # 按行号从小到大排序,保证行顺序正确 for row_idx in sorted(rows_dict.keys()): row_data = [] # 逐列补全空单元格 for col_idx in range(1, max_col + 1): cell_text = rows_dict[row_idx].get(col_idx, "").strip() row_data.append(cell_text) table_matrix.append(row_data) return table_matrix
解析所有表格时,直接将每个表格的二维矩阵存入独立列表all_tables,不再做字符串拼接。
3. 指定键值对提取逻辑
基于开启FORMS特征后返回的键值对元数据,编写匹配逻辑提取目标内容:
- 从blocks集合中筛选出类型为
KEY_VALUE_SET、实体类型为KEY的块,作为所有候选键的来源。 - 通过块自带的关联关系,找到每个键对应的VALUE块,提取完整文本作为对应取值。
- 按照需求筛选目标键(如「Example 1」「Example 2」),生成目标键值对字典。
对应的函数示例:
def extract_target_kv(blocks_map): kv_pairs = {} # 筛选所有KEY类型的块 key_blocks = [ block for block in blocks_map.values() if block['BlockType'] == 'KEY_VALUE_SET' and block['EntityTypes'][0] == 'KEY' ] for key_block in key_blocks: key_text = get_text(key_block, blocks_map).strip() # 查找键关联的VALUE块ID value_block_id = None for rel in key_block.get('Relationships', []): if rel['Type'] == 'VALUE': value_block_id = rel['Ids'][0] break if not value_block_id: continue # 提取值文本 value_text = get_text(blocks_map[value_block_id], blocks_map).strip() kv_pairs[key_text] = value_text # 筛选需要的目标键 target_key_list = ["Example 1", "Example 2"] return {k:v for k,v in kv_pairs.items() if k in target_key_list}
4. 规范Excel输出实现
通过openpyxl库实现多工作表写入,首先安装依赖:pip install openpyxl
按照需求将数据分类写入不同工作表:
- 每个提取到的表格单独占用一个工作表,命名为
Table_1、Table_2,对应表格的实际顺序。 - 单独新建一个
KeyValues工作表,存放提取到的所有目标键值对,方便后续映射处理。
对应的写入函数示例:
from openpyxl import Workbook def write_structured_excel(all_tables, target_kv, output_path="structured_output.xlsx"): wb = Workbook() # 删除默认创建的空白工作表 wb.remove(wb.active) # 逐表写入对应工作表 for table_idx, table_data in enumerate(all_tables, start=1): ws = wb.create_sheet(title=f"Table_{table_idx}") for row in table_data: ws.append(row) # 写入键值对工作表 ws_kv = wb.create_sheet(title="KeyValues") ws_kv.append(["键名", "对应取值"]) for key, value in target_kv.items(): ws_kv.append([key, value]) wb.save(output_path)
落地注意事项
get_text函数提取的文本会因为逐单词拼接带前后空格,所有键名、单元格文本提取后要做strip()处理,避免因为多余空格导致的键名匹配失败。- 遇到跨页表格时,可以利用blocks自带的
Page属性,将同一页面的表格归组,避免不同页的表格混排。 - 写Excel时不要把所有表格堆在同一个工作表中,拆分工作表的结构完全匹配实际PDF中的表格边界,后续做数据映射时不需要再手动拆分内容。
内容的提问来源于stack exchange,提问作者Manz
相关产品推荐
相关产品推荐

