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

如何从PDF提取嵌入的CSV/Excel文件?已试PyPDF2等工具未果

从PDF提取嵌入CSV/Excel文件的解决方案

你之前的代码存在几个容易导致失败的问题,比如依赖旧版PyPDF2 API、遍历嵌入文件的方式不可靠,还有没覆盖PDF中嵌入文件的所有可能存储位置。下面是修复后的方案,还有更简便的替代工具:

问题排查

你的原代码问题点:

  • 用了PyPDF2的旧版API(PdfFileReader现在已经被PdfReader替代)
  • 用index(f)找文件对象的方式有bug,如果PDF里有重名嵌入文件,会匹配到错误的对象
  • 只处理了根目录下的/EmbeddedFiles,但有些PDF会把嵌入文件存在表单域(/AcroForm)里
  • 没有异常处理,一旦PDF结构不符合预期直接报错

修复后的PyPDF2代码

用最新API,覆盖更多嵌入文件存储场景,避免重名问题:

import PyPDF2
import os

def extract_embedded_files(pdf_path, output_dir):
    # 自动创建输出文件夹
    os.makedirs(output_dir, exist_ok=True)
    
    with open(pdf_path, 'rb') as pdf_file:
        reader = PyPDF2.PdfReader(pdf_file)
        attachments = {}
        
        # 处理文档根目录下的嵌入文件
        root = reader.trailer['/Root']
        if '/Names' in root and '/EmbeddedFiles' in root['/Names']:
            embedded_entries = root['/Names']['/EmbeddedFiles']['/Names']
            # 成对遍历:文件名和文件对象是交替出现的,直接按步长2遍历更可靠
            for i in range(0, len(embedded_entries), 2):
                filename = embedded_entries[i]
                if isinstance(filename, str):
                    file_obj = embedded_entries[i+1].get_object()
                    if '/EF' in file_obj and '/F' in file_obj['/EF']:
                        file_data = file_obj['/EF']['/F'].get_data()
                        attachments[filename] = file_data
        
        # 处理表单域中的嵌入文件(部分PDF会存在这里)
        if '/AcroForm' in root and '/Fields' in root['/AcroForm']:
            for field in root['/AcroForm']['/Fields']:
                field_obj = field.get_object()
                # 判断是否是文件域
                if field_obj.get('/FT') == '/F' and '/EF' in field_obj and '/F' in field_obj['/EF']:
                    filename = field_obj.get('/F', 'unknown_file')
                    file_data = field_obj['/EF']['/F'].get_data()
                    attachments[filename] = file_data
        
        # 保存所有提取到的文件
        for filename, data in attachments.items():
            # 清理文件名里的非法字符
            safe_name = os.path.basename(filename).replace('/', '_').replace('\\', '_')
            save_path = os.path.join(output_dir, safe_name)
            with open(save_path, 'wb') as out_file:
                out_file.write(data)
            print(f"提取完成:{save_path}")

# 替换成你的PDF路径和输出文件夹名
extract_embedded_files("your_pdf.pdf", "extracted_files")

更省心的替代方案:用PyMuPDF(fitz)

PyMuPDF对各种PDF结构的兼容性更好,代码也更简洁,推荐试试:

import fitz
import os

def extract_with_pymupdf(pdf_path, output_dir):
    os.makedirs(output_dir, exist_ok=True)
    doc = fitz.open(pdf_path)
    
    # 提取页面上的嵌入文件注释
    for page in doc:
        for annot in page.annots():
            if annot.type[0] == 17:  # 标注类型为嵌入文件
                filename = annot.info['content']
                file_data = annot.get_file()
                safe_name = os.path.basename(filename).replace('/', '_').replace('\\', '_')
                save_path = os.path.join(output_dir, safe_name)
                with open(save_path, 'wb') as f:
                    f.write(file_data)
                print(f"提取完成:{save_path}")
    
    # 提取文档级的嵌入文件
    for name in doc.embfile_names():
        file_data = doc.embfile_get(name)
        safe_name = os.path.basename(name).replace('/', '_').replace('\\', '_')
        save_path = os.path.join(output_dir, safe_name)
        with open(save_path, 'wb') as f:
            f.write(file_data)
        print(f"提取完成:{save_path}")

# 使用示例
extract_with_pymupdf("your_pdf.pdf", "extracted_files")

额外提示

  • 先安装需要的库:pip install PyPDF2 pymupdf
  • 如果PDF加密了,要先解密:PyPDF2用reader.decrypt("密码"),PyMuPDF在打开时加fitz.open(pdf_path, password="你的密码")
  • 如果还是提取不到,先试试用Adobe Acrobat手动提取,确认PDF里确实有可提取的嵌入文件(有些PDF的“嵌入”其实是把内容转成了PDF内容,不是真正的附件)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:32:49