You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用pdfplumber处理含合并单元格的PDF表格?

处理PDF中带合并单元格的表格解析并转为JSON

原代码使用extract_tables的线条分割策略,无法识别合并单元格的跨度,导致提取后合并单元格对应位置出现空值,无法正确映射到JSON结构。以下是针对性解决方案:

核心思路

通过layout=True参数提取表格的单元格布局信息(包含坐标、行/列跨度),再根据这些信息填充合并单元格的内容,确保每行数据字段完整后,转换为JSON格式。

修改后的完整代码

def is_valid_table(table):
    min_rows, min_columns = 1, 2
    return len(table) >= min_rows and len(table[0]) >= min_columns

def extract_layout_tables(page):
    # 启用layout参数获取单元格布局信息
    tables = page.extract_tables({
        "vertical_strategy": "lines",
        "horizontal_strategy": "lines",
        "edge_min_length": 15,
        "min_words_vertical": 1,
        "layout": True  # 关键参数:获取单元格的行/列跨度
    })
    return [table for table in tables if is_valid_table(table)]

def merge_cells(table):
    processed_table = []
    # 复制原始表格避免修改原数据
    for row in table:
        processed_table.append([cell.copy() for cell in row])
    
    # 处理跨行合并单元格
    for row_idx in range(len(processed_table)):
        for col_idx in range(len(processed_table[row_idx])):
            cell = processed_table[row_idx][col_idx]
            if cell['rowspan'] > 1 and cell['text']:
                # 将内容填充到下方对应行
                for offset in range(1, cell['rowspan']):
                    if row_idx + offset < len(processed_table):
                        processed_table[row_idx + offset][col_idx]['text'] = cell['text']
    
    # 处理跨列合并单元格
    for row_idx in range(len(processed_table)):
        col_idx = 0
        while col_idx < len(processed_table[row_idx]):
            cell = processed_table[row_idx][col_idx]
            if cell['colspan'] > 1 and cell['text']:
                # 将内容填充到右侧对应列
                for offset in range(1, cell['colspan']):
                    if col_idx + offset < len(processed_table[row_idx]):
                        processed_table[row_idx][col_idx + offset]['text'] = cell['text']
            col_idx += 1
    
    # 提取纯文本表格
    text_table = []
    for row in processed_table:
        text_row = [cell['text'] if cell['text'] else '' for cell in row]
        text_table.append(text_row)
    return text_table

# 主处理流程
valid_tables = extract_layout_tables(page)
page_text = page.extract_text()
pdf_data["tables"] = []

for table in valid_tables:
    processed_text_table = merge_cells(table)
    
    # 匹配表格起始位置并获取标题(复用原有find_table_title函数)
    table_start_text = "\n".join(["".join(cell) for cell in processed_text_table])
    table_start_index = page_text.find(table_start_text)
    table_title = find_table_title(page_text, table_start_index)
    
    # 转换为JSON结构
    headers = processed_text_table[0]
    table_data = [dict(zip(headers, row)) for row in processed_text_table[1:]]
    
    pdf_data["tables"].append({
        "title": table_title,
        "page_number": page.page_number,
        "data": table_data
    })

代码说明

  1. extract_layout_tables函数:添加layout=True后,每个单元格变为包含text(内容)、rowspan(跨行数)、colspan(跨列数)的字典,为合并单元格处理提供依据。
  2. merge_cells函数:
    • 跨行合并:将合并单元格内容填充到下方所有属于该合并范围的单元格
    • 跨列合并:将合并单元格内容填充到右侧所有属于该合并范围的单元格
    • 最终输出纯文本的完整表格,确保每行每列都有对应内容
  3. JSON转换逻辑:基于处理后的完整纯文本表格,复用原有标题匹配和字典映射逻辑,保证输出JSON结构正确。

注意事项

  • 若PDF表格线条不清晰,可将vertical_strategy和horizontal_strategy改为text(基于文本位置分割),但lines策略对带明确边框的表格更准确。
  • 若合并单元格跨度识别不准确,可微调edge_min_length等参数,或添加额外逻辑验证单元格坐标范围。

内容的提问来源于stack exchange,提问作者Santhosh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:15:21