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

PDF发票数据提取代码报错:AttributeError: 'NoneType' object无'group'属性

问题解决:AttributeError: 'NoneType' object has no attribute 'group' 及PDF发票数据提取优化

错误根源

  1. 正则表达式语法错误:你用d\+匹配数字,但正确的数字匹配正则是\d+,少了反斜杠导致完全匹配不到目标内容,re.search返回None,调用group()自然触发错误。
  2. 未做匹配失败兜底:即便正则写对,也可能遇到格式特殊的PDF,直接调用group()会导致程序崩溃。
  3. 数据结构处理错误:flat_data把每个PDF的四条数据拆成单个元素,生成的Excel只会有一列,完全不符合预期结构。

修复后的完整代码

import pandas as pd
import os
import pdfplumber
import re

# 读取基础Excel(若不需要可直接删除这段)
path_base = rf'C:/Users/{os.getlogin()}/OneDrive - Falabella/Documentos - Desarrollo Logistico/Proyectos Desarrollo Interno/Proyectos Internos/Confimación y Facturación Apple/Base proveedor/Base-prueba.xlsx'
detalle_base = pd.read_excel(path_base, sheet_name="Base")
detalle_base = detalle_base.reindex(columns=[
    'Factura', 'New OC', 'PRODUCTO', 'NOMBRE', 'Units', 
    'CAJAS', 'SKU Falabella', 'Costo Unitario', 'Monto total', 
    'Diferencia Informada', 'Comentarios'
])

def extract_pdf_data(file_names):
    all_data = []
    for file_name in file_names:
        with pdfplumber.open(file_name) as pdf:
            page = pdf.pages[0]
            text = page.extract_text()
            # 修复正则+添加匹配失败兜底
            num_fact_match = re.search(r'N°\s*(\d+)', text)
            numero_factura = num_fact_match.group(1) if num_fact_match else '未找到'
            
            cant_match = re.search(r'Cant\.\s*(\d+)', text)
            cantidad = cant_match.group(1) if cant_match else '未找到'
            
            costo_match = re.search(r'Valor unitario\s*(\d+\.?\d*)', text)
            costo_unitario_fact = costo_match.group(1) if costo_match else '未找到'
            
            total_match = re.search(r'Valor\s*(\d+\.?\d*)', text)
            valor_total_fact = total_match.group(1) if total_match else '未找到'
            
            all_data.append([numero_factura, cantidad, costo_unitario_fact, valor_total_fact])
    return all_data

def convert_pdfs_to_excel(directory, excel_save_path):
    # 兼容大小写后缀的PDF文件
    file_names = [
        os.path.join(directory, f) 
        for f in os.listdir(directory) 
        if f.lower().endswith('.pdf')
    ]
    all_data = extract_pdf_data(file_names)
    # 直接用二维列表生成DataFrame,保证四列结构
    df = pd.DataFrame(
        all_data, 
        columns=['Numero Factura', 'Cantidad', 'Costo Unitario', 'Valor Total']
    )
    df.to_excel(excel_save_path, index=False)

# 执行调用
pdf_directory = rf'C:/Users/{os.getlogin()}/OneDrive - Falabella/Documentos - Desarrollo Logistico/Proyectos Desarrollo Interno/Proyectos Internos/Confimación y Facturación Apple/Facturas Apple'
excel_output_path = rf'C:/Users/{os.getlogin()}/OneDrive - Falabella/Documentos - Desarrollo Logistico/Proyectos Desarrollo Interno/Proyectos Internos/Confimación y Facturación Apple/datos.xlsx'
convert_pdfs_to_excel(pdf_directory, excel_output_path)

核心修复说明

  • 正则修正:把d\+改成\d+匹配整数,金额类字段用\d+\.?\d*兼容整数和小数格式。
  • 容错机制:每次匹配后先判断是否找到结果,未匹配到则填充“未找到”,避免程序崩溃。
  • 数据结构修复:删除错误的flat_data处理,直接用每个PDF对应的列表生成Excel行,保证四列的正确结构。
  • 路径优化:用f-string简化路径拼接,同时兼容大写后缀的PDF文件。

额外提示

  • 如果部分发票是表格形式,pdfplumber的extract_table()方法比纯文本提取更靠谱,可以尝试用它直接提取结构化表格数据。
  • 可添加打印语句输出正在处理的文件名,方便排查单个PDF的提取异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 17:23:13