PyPDF2提取PDF中ZUGFeRD嵌入式XML失败问题排查
PyPDF2提取PDF中ZUGFeRD嵌入式XML失败问题排查
我明白你现在的困扰——在线工具能轻松从PDF里提取到ZUGFeRD XML,但自己用PyPDF2写的函数却一直提示“找不到嵌入式ZUGFeRD XML文件”,肯定摸不着头脑吧?咱们来一步步拆解问题,找到原因和解决办法。
你当前代码的核心问题:找错了嵌入式文件的存储位置
你现在的代码是循环每个PDF页面,在页面对象里找/EmbeddedFiles,但ZUGFeRD XML作为标准的嵌入式附件,根本不是存在页面对象里的!它的标准存储位置是在PDF文档的根字典(Root)下的/Names/EmbeddedFiles集合里,这是PDF规范中存放嵌入式文件的默认位置,在线工具也是按照这个规范查找的,而你的代码方向从一开始就错了。
另外,你的代码里还有个小bug:在循环页面的时候重复创建了pdf_reader对象,这会导致已打开的文件指针混乱,完全没必要这么做。
正确的查找逻辑:从文档根节点的Names字典入手
咱们重新梳理正确的提取流程:
- 打开PDF后,获取文档的根字典(通过
pdf_reader.root) - 检查根字典中是否存在
/Names键,里面是否包含/EmbeddedFiles条目 - 遍历
/EmbeddedFiles下的文件列表,筛选出ZUGFeRD相关的XML文件 - 提取该文件的原始内容并解码为字符串
修正后的代码示例
import PyPDF2 def extract_zugferd_xml(pdf_file_path): """ Extracts the ZUGFeRD XML from a PDF file and returns it as a string. Args: pdf_file_path (str): The path to the PDF file to extract the XML from. Returns: str: The ZUGFeRD XML as a string. """ with open(pdf_file_path, 'rb') as pdf_file: pdf_reader = PyPDF2.PdfReader(pdf_file) root = pdf_reader.root # 检查文档根节点是否有Names字典,且包含EmbeddedFiles if '/Names' not in root or '/EmbeddedFiles' not in root['/Names']: raise ValueError('The specified PDF file does not contain embedded files.') embedded_files_names = root['/Names']['/EmbeddedFiles']['/Names'] # PDF的Names数组结构是 [文件名1, 文件对象1, 文件名2, 文件对象2, ...] for i in range(0, len(embedded_files_names), 2): file_name = embedded_files_names[i] file_obj_ref = embedded_files_names[i+1] # 获取文件对象的实际内容 file_obj = pdf_reader.get_object(file_obj_ref) file_stream = file_obj['/EF']['/F'] xml_content = file_stream.get_data().decode('utf-8') # 筛选ZUGFeRD XML:文件名通常带ZUGFeRD,或者内容里包含ZUGFeRD标识 if (file_name.endswith('.xml') and 'ZUGFeRD' in xml_content) or 'zugferd' in file_name.lower(): return xml_content # 遍历完所有嵌入式文件都没找到 raise ValueError('The specified PDF file does not contain an embedded ZUGFeRD XML file.')
额外说明
- 为什么在线工具能找到?因为在线工具严格遵循了PDF规范,从文档级的嵌入式文件集合里查找,而你的代码错误地去页面对象里找,自然找不到。
- 少数特殊的ZUGFeRD PDF可能会把XML存放在AcroForm的嵌入式文件集合里,如果上面的代码还是找不到,可以尝试检查
pdf_reader.root.get('/AcroForm', {}).get('/EmbeddedFiles'),但这种情况非常少见。
备注:内容来源于stack exchange,提问作者Djoni Djonovic
相关产品推荐
相关产品推荐

