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

如何用Python提取复杂布局PDF中的文本并保留结构?

复杂PDF布局的结构化文本提取方案

针对双栏、带边框/无边框表格、双栏嵌套表格、相邻表格这类复杂组合场景,单纯用PyMuPDF的基础API确实搞不定布局区分,得结合布局特征识别+针对性提取逻辑,以下是落地方法:

1. 先给PDF页面做布局分类(基于PyMuPDF的bbox分析)

用page.get_text("dict")拿到的布局数据里,每个文本块都有bbox坐标(x1,y1,x2,y2),靠这个先判断布局类型:

  • 双栏判定:计算页面中线mid_x = page.rect.width / 2,统计所有文本块的x1坐标,若70%以上的块集中在中线两侧(且单块宽度<mid_x*0.9),直接标记为双栏布局
  • 表格判定:不管有无边框,看文本块的对齐特征:连续多个块的y坐标高度差极小(行对齐)、x坐标有规律分段(列对齐)、块间距远小于普通段落行间距,满足这些就标记为表格区域

2. 分场景针对性提取

双栏文本提取

把页面按中线切分成左右两个区域,分别对每个区域的文本块按y坐标从小到大排序(同一y区间内按x排序),保证内容按阅读顺序输出:

import fitz

def extract_two_column_content(page):
    page_rect = page.rect
    mid_x = page_rect.width / 2
    left_blocks, right_blocks = [], []
    layout_dict = page.get_text("dict")
    
    for block in layout_dict["blocks"]:
        if block["type"] == 0:  # 筛选文本块
            block_left_x = block["bbox"][0]
            if block_left_x < mid_x:
                left_blocks.append(block)
            else:
                right_blocks.append(block)
    
    # 按垂直位置排序,同一行内按水平位置排序
    def sort_by_position(blocks):
        return sorted(blocks, key=lambda b: (b["bbox"][1], b["bbox"][0]))
    
    # 提取左右栏文本
    def blocks_to_text(blocks):
        return "\n".join([line["text"] for b in blocks for line in b["lines"]])
    
    left_text = blocks_to_text(sort_by_position(left_blocks))
    right_text = blocks_to_text(sort_by_position(right_blocks))
    return f"{left_text}\n\n{right_text}"

表格提取(含无边框/双栏内表格)

  • 用PyMuPDF的page.get_text("table")直接提取表格结构,这个API会靠文本对齐识别无边框表格,返回的是二维列表,直接对应表格行列
  • 双栏内的表格:先通过表格的bbox判断属于左/右栏,提取完表格结构后,把表格转换成Markdown格式,插入到对应栏的文本对应位置
  • 相邻表格:判断两个表格的上下bbox间距,若小于普通段落行间距的2倍,就合并成一个大表格处理,避免拆分成两个独立表格

组合场景处理

如果遇到双栏+嵌套表格的情况,流程是:

  1. 标记页面的双栏区域和表格区域
  2. 先提取表格的结构化数据,用占位符(比如[TABLE])替换表格位置的文本块
  3. 按双栏逻辑提取普通文本
  4. 把占位符替换成格式化的表格内容

3. 工具组合补短板

如果PyMuPDF的表格提取不够准,搭配pdfplumber:

  • 用PyMuPDF做全局布局分类(双栏/单栏、表格位置标记)
  • 用pdfplumber的pdf.pages[i].extract_table()提取表格,它对复杂边框、合并单元格的支持更好

4. 保证结构不丢失

不要直接输出纯文本,而是输出结构化数据:

# 示例结构化输出格式
page_result = {
    "layout_type": "two_column",
    "left_content": {
        "text": "左栏普通文本...",
        "tables": [{"rows": [["单元格1", "单元格2"], ["单元格3", "单元格4"]]}]
    },
    "right_content": {
        "text": "右栏普通文本...",
        "tables": []
    }
}

后续可以根据需求转换成纯文本、Markdown或JSON,完全保留原始布局结构

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:20:12