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

PyMuPDF提取多PDF数据至CSV仅获首页内容问题排查

解决多页PDF信息提取不全的问题

问题根源分析

你的代码出现提取不全的问题,核心原因有两点:

  • 正则表达式重复/匹配失效:R_P_pattern和R_T_pattern完全一致,会导致两者匹配同一内容甚至互相干扰;同时PDF文本常存在换行,你的正则默认不支持跨行匹配,导致后续页面的目标文本被换行打断后无法命中。
  • 缺少调试反馈:无法直观看到每个页面的匹配情况,难以定位是页面文本加载失败,还是正则规则不匹配。

解决方案步骤

  1. 修正重复正则:为R_P和R_T编写独立的正则规则,精准匹配各自的目标字段。
  2. 添加跨行匹配标志:给所有正则匹配添加re.DOTALL(让.匹配换行符)和re.UNICODE(处理特殊字符),适配PDF文本的换行场景。
  3. 增加调试输出:在页面循环中打印匹配结果,快速定位未命中的字段和对应页面。

修正后的代码

import os
import csv
import re
import fitz

# 修正正则:区分R_P和R_T的匹配规则(需根据实际PDF文本调整)
I_T_Pattern = r'Lorem ipsum dolor sit amet (\w+ \d{1,2}, \d{4}) \(Lorem ipsum dolor sit amet\)'
# 示例:假设R_P的文本末尾带有特定标识
R_P_pattern = r'Lorem ipsum dolor sit amet (\d+) Lorem ipsum dolor sit amet - RP'
# 示例:假设R_T的文本开头带有特定标识
R_T_pattern = r'RT - Lorem ipsum dolor sit amet (\d+) Lorem ipsum dolor sit amet'
NON_R_pattern = r'Lorem ipsum dolor sit amet (\d+)'
E_D_pattern = r'Lorem ipsum dolor sit amet \(“Lorem ipsum dolor sit amet”\), Lorem ipsum dolor sit amet (\w+ \d{1,2}, \d{4})'
L_pattern = r'“Lorem ipsum dolor sit amet”\)\.(\s+)(\w+[\s\w]*),'

def extract_contract_data(pdf_file):
    doc = fitz.open(pdf_file)
    I_T = None
    R_P = None
    R_T = None
    NON_R = None
    E_D = None
    L = None

    for page_num in range(doc.page_count):
        page = doc.load_page(page_num)
        text = page.get_text()
        
        # 调试用:打印当前页面文本(可根据需求注释)
        # print(f"\n--- 第 {page_num+1} 页文本 ---")
        # print(text)

        # 启用跨行匹配,适配PDF文本换行
        I_T_match = re.search(I_T_Pattern, text, re.DOTALL | re.UNICODE)
        R_P_match = re.search(R_P_pattern, text, re.DOTALL | re.UNICODE)
        R_T_match = re.search(R_T_pattern, text, re.DOTALL | re.UNICODE)
        NON_R_match = re.search(NON_R_pattern, text, re.DOTALL | re.UNICODE)
        E_D_match = re.search(E_D_pattern, text, re.DOTALL | re.UNICODE)
        L_match = re.search(L_pattern, text, re.DOTALL | re.UNICODE)

        # 调试用:打印当前页面各字段匹配结果
        print(f"第 {page_num+1} 页匹配结果:")
        print(f"I_T: {I_T_match.group(1) if I_T_match else '未找到'}")
        print(f"R_P: {R_P_match.group(1) if R_P_match else '未找到'}")
        print(f"R_T: {R_T_match.group(1) if R_T_match else '未找到'}")
        print(f"NON_R: {NON_R_match.group(1) if NON_R_match else '未找到'}")
        print(f"E_D: {E_D_match.group(1) if E_D_match else '未找到'}")
        print(f"L: {L_match.group(2) if L_match else '未找到'}")

        # 仅在字段未赋值时更新
        if I_T_match and not I_T:
            I_T = I_T_match.group(1)
        if R_P_match and not R_P:
            R_P = R_P_match.group(1)
        if R_T_match and not R_T:
            R_T = R_T_match.group(1)
        if NON_R_match and not NON_R:
            NON_R = NON_R_match.group(1)
        if E_D_match and not E_D:
            E_D = E_D_match.group(1)
        if L_match and not L:
            L = L_match.group(2)

    doc.close()
    return {
        "L": L,
        "E D": E_D,
        "I T": I_T,
        "R P": R_P,
        "R T": R_T,
        "NON R": NON_R
    }

def main():
    pdf_dir = r'C:\\path'
    pdf_files = [os.path.join(pdf_dir, f) for f in os.listdir(pdf_dir) if f.endswith(".pdf")]
    data = []

    for pdf_file in pdf_files:
        print(f"\n=== 处理文件:{os.path.basename(pdf_file)} ===")
        contract_data = extract_contract_data(pdf_file)
        data.append(contract_data)

    output_file = r'C:\\output.csv'
    with open(output_file, "w", newline='', encoding='utf-8') as file:
        fieldnames = ["L", "E D", "I T", "R P", "R T", "NON R"]
        writer = csv.DictWriter(file, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(data)

    print(f"\n结果已保存至:{output_file}")

if __name__ == "__main__":
    main()

额外注意事项

  • 你需要根据实际PDF中的文本内容,调整R_P_pattern和R_T_pattern的具体规则,确保它们能分别匹配到对应页面的目标字段。
  • 如果调试发现某些页面文本提取不全,可能是PDF为扫描件格式(fitz无法提取文本),这种情况需要配合OCR工具(如pytesseract)处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 05:23:16