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

如何从无固定模式的PDF文件中提取目标文本片段

PDF指定章节提取可行实现方案

纯文本提取丢失PDF原生排版、位置信息,是导致行顺序错乱、锚点失效的核心原因,按以下思路实现可覆盖所有提到的问题场景:

  • 放弃直接导出纯文本的方案,提取阶段保留完整布局元数据
    不要直接调用pdfminer.six的extract_text()方法输出无结构txt,改用extract_pages()接口遍历页面元素,配合调整后的LAParams参数做布局分析,为每个文本块记录x/y坐标、字号、字体、字重属性。提取完成后对所有文本块按视觉顺序重排:以y坐标降序排序(PDF坐标原点在页面左下角,y值越大位置越靠上),同一y轴区间内的块按x坐标升序排序,从根源解决第二个文件里文本顺序错乱的问题——纯文本提取默认按PDF内部对象存储顺序输出,本身就不保证和人眼看到的阅读顺序一致。

  • 靠视觉特征锚定章节标题,不依赖固定行号、硬正则
    人眼能识别章节标题,本质是标题和正文存在明确视觉差异:通常比正文字号大2pt以上、字体加粗、和前后段落的间距大于普通正文行间距。遍历重排后的文本块时,先筛选符合标题视觉特征的块,再匹配块内文本是否为目标章节标题即可。如果遇到标题和其他内容混排在同一提取行的情况,可以进一步拆分到单个字符维度,靠字体差异、字符间的异常大间距把标题从混排内容里拆分出来,不会漏匹配。

  • 锚定标题后按排版边界提取内容,不依赖固定行偏移
    定位到标题块的坐标后,从标题下方第一个符合正文特征的文本块开始收集内容,直到遇到下一个同等级/更高等级的标题(同样靠字号、加粗、间距特征判断)就停止提取。结合目标内容左右边距固定的特征,加一层过滤规则:只保留x坐标范围落在目标内容边距区间内的文本块,自动排除页眉、页脚、侧边注释、页码等干扰内容,不需要关心标题前有多少未知段落。

  • 增加模糊匹配兜底逻辑适配异常文件
    如果遇到少数标题格式和正文完全一致的特殊PDF,可以加一层轻量的文本相似度校验(比如编辑距离匹配),结合位置特征排除误匹配,不需要写复杂的通用正则。

最小可运行参考代码

from pdfminer.high_level import extract_pages
from pdfminer.layout import LTTextLineHorizontal, LAParams

# 布局分析参数,可根据PDF排版微调
laparams = LAParams(
    line_overlap=0.5,
    char_margin=2.0,
    line_margin=0.5,
    word_margin=0.1,
    detect_vertical=False
)

# 配置项,根据实际PDF参数校准一次即可,同模板文件通用
TARGET_SECTION_TITLE = "Important section title"
CONTENT_LEFT_MARGIN = 72   # 目标内容左边距
CONTENT_RIGHT_MARGIN = 540 # 目标内容右边距
BODY_FONT_SIZE = 12        # 正文字号

def extract_target_section(pdf_path):
    text_blocks = []
    # 逐页提取带元数据的文本块
    for page in extract_pages(pdf_path, laparams=laparams):
        for elem in page:
            if isinstance(elem, LTTextLineHorizontal):
                # 提取当前行的核心属性
                font_sizes = []
                is_bold = False
                for char in elem:
                    if hasattr(char, "size"):
                        font_sizes.append(char.size)
                    if hasattr(char, "fontname") and "Bold" in char.fontname:
                        is_bold = True
                text_blocks.append({
                    "y_top": elem.y1,
                    "x0": elem.x0,
                    "x1": elem.x1,
                    "content": elem.get_text().strip(),
                    "font_size": max(font_sizes) if font_sizes else BODY_FONT_SIZE,
                    "is_bold": is_bold
                })
    # 按人眼阅读顺序重排所有文本块
    text_blocks.sort(key=lambda x: (-x["y_top"], x["x0"]))

    # 定位目标标题位置
    title_pos = None
    for idx, block in enumerate(text_blocks):
        if TARGET_SECTION_TITLE in block["content"] and (block["is_bold"] or block["font_size"] > BODY_FONT_SIZE):
            title_pos = idx
            break
    if title_pos is None:
        return ""

    # 提取标题到下一个标题之间的目标内容
    result = []
    for block in text_blocks[title_pos+1:]:
        # 遇到下一个标题则终止提取
        if block["is_bold"] or block["font_size"] > BODY_FONT_SIZE:
            break
        # 过滤边距不符合的非目标内容
        if block["x0"] >= CONTENT_LEFT_MARGIN and block["x1"] <= CONTENT_RIGHT_MARGIN:
            if block["content"]:
                result.append(block["content"])
    return "\n".join(result)

上述代码里的边距、字号参数只需要校准一次,同模板生成的所有PDF都可以通用,不需要针对单个文件调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 00:24:31