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

基于Python提取多格式PDF特定文本的实现方案咨询

多格式PDF定向文本提取落地方案

针对多排版PDF定向提取适配难、规则不统一的问题,直接采用带格式元数据提取+可配置规则集的方案即可,不需要堆叠多个独立库,核心用PyMuPDF就能覆盖绝大多数场景,比纯文本正则的适配性高一个量级。


核心实现逻辑

你之前调用PyMuPDF、pdfplumber只取了纯文本内容,完全浪费了库能拿到的格式元数据:每个文本片段的字体大小、是否加粗、坐标位置、特殊字符标记、字体类型这些信息,才是做定向区间提取的核心依据,比纯文本关键词匹配靠谱得多。

  • 第一类PDF(从Case 1提取到加粗菱形◆标记):不需要写正则硬找菱形符号,直接遍历所有文本片段,当片段包含◆字符且属于加粗格式时,标记为区间终止点;找到文本以"Case"加数字开头的片段位置作为起始点,拼接两个位置之间的所有文本即可,完全不受换行、缩进、跨页拆分的影响。
  • 第二类PDF(按history/examination/investigations章节切分):这类医学文档的章节标题普遍有固定格式特征(加粗、字号大于正文、单独占行),先把所有符合标题特征的文本块按从上到下的阅读顺序排序,再按标题名切分相邻标题之间的内容块即可,不会因为不同PDF的标题大小写、前后多余空格、标点差异匹配失败。

多格式适配方案

不要把提取逻辑硬编码在脚本里,做一层可配置规则层,核心提取逻辑完全复用,新增PDF格式只需要加一条规则配置,不需要重写代码:

  • 每类PDF的规则配置仅需定义3类信息:起始位置匹配规则(支持关键词、加粗/字号等格式特征)、终止/切分位置匹配规则、需要导出的字段名
  • 配置示例:
# 第一类PDF提取规则
PDF_TYPE1_RULE = {
    "match_type": "range",
    "start": {"keyword": "Case", "is_bold": False},
    "end": {"keyword": "◆", "is_bold": True},
    "export_fields": ["case_content"]
}

# 第二类PDF提取规则
PDF_TYPE2_RULE = {
    "match_type": "section_split",
    "section_titles": ["history", "examination", "investigations"],
    "title_format": {"is_bold": True},
    "export_fields": ["history", "investigation"]
}

代码启动时先做PDF类型自动识别(可通过文档抬头、固定位置的特殊标识判断),自动加载对应规则执行提取即可,你手里剩下的5种以上格式PDF,每加一种只需要写10行以内的配置,维护成本极低。

兜底处理方案

  • 遇到扫描版PDF:直接用PyMuPDF内置的OCR能力对接Tesseract,识别时保留每个文本块的坐标、置信度信息,和可编辑PDF的处理逻辑完全打通,不需要单独写一套OCR提取代码。
  • 遇到文本块顺序错乱的PDF:所有提取到的文本块先按纵向坐标(上下位置)优先、横向坐标(缩进位置)次之排序,再做区间匹配,能解决90%以上排版错乱导致的内容顺序不对问题。

核心代码示例

基于PyMuPDF实现,替换了你之前只提取纯文本的逻辑,支持格式判断:

import fitz
import pandas as pd

def load_all_spans(pdf_path):
    """加载PDF所有文本片段,附带格式属性"""
    doc = fitz.open(pdf_path)
    all_spans = []
    for page in doc:
        page_blocks = page.get_text("dict")["blocks"]
        for block in page_blocks:
            if "lines" not in block:
                continue
            for line in block["lines"]:
                for span in line["spans"]:
                    # 追加加粗判断属性
                    span["is_bold"] = bool(span["flags"] & 16)
                    span["text_stripped"] = span["text"].strip().lower()
                    all_spans.append(span)
    doc.close()
    return all_spans

def extract_by_rule(spans, rule):
    """按配置规则提取目标内容"""
    result = {field: "" for field in rule["export_fields"]}
    if rule["match_type"] == "range":
        # 区间提取逻辑
        start_idx = None
        end_idx = None
        for idx, span in enumerate(spans):
            if start_idx is None and rule["start"]["keyword"] in span["text"] and span["is_bold"] == rule["start"]["is_bold"]:
                start_idx = idx
            if start_idx is not None and rule["end"]["keyword"] in span["text"] and span["is_bold"] == rule["end"]["is_bold"]:
                end_idx = idx
                break
        if start_idx is not None and end_idx is not None:
            result[rule["export_fields"][0]] = "".join([s["text"] for s in spans[start_idx:end_idx]]).strip()
    
    elif rule["match_type"] == "section_split":
        # 章节切分逻辑
        title_pos = []
        for idx, span in enumerate(spans):
            if span["text_stripped"] in rule["section_titles"] and span["is_bold"] == rule["title_format"]["is_bold"]:
                title_pos.append((idx, span["text_stripped"]))
        for i in range(len(title_pos)-1):
            cur_idx, cur_title = title_pos[i]
            next_idx = title_pos[i+1][0]
            if cur_title in result:
                result[cur_title] = "".join([s["text"] for s in spans[cur_idx+1:next_idx]]).strip()
    return result

if __name__ == "__main__":
    all_extract_result = []
    # 此处可加自动识别PDF类型、加载对应规则的逻辑
    test_rule = PDF_TYPE2_RULE
    spans = load_all_spans("target_file.pdf")
    all_extract_result.append(extract_by_rule(spans, test_rule))
    # 导出到Excel
    pd.DataFrame(all_extract_result).to_excel("extract_output.xlsx", index=False)

避坑提示:不要把纯文本正则作为核心匹配逻辑,纯文本丢失了所有格式信息,只要PDF出现换行、多余空格、特殊字符编码差异就会匹配失效,结合格式特征的匹配准确率普遍能达到95%以上。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 20:27:21