要点总结:
- Python 可以帮助你自动化提取发票数据,但没有“银弹”式的绝对方案
- Parseur 利用 Python 为你提取发票数据
- PDF 并非数据文件格式,而是纸质文档的版面表现形式
PDF格式
PDF 格式非常灵活,能够精准呈现如发票等纸质文档,并且对页面设计没有限制。 PDF 源自纸质打印领域,旨在作为打印页面的数字化等效物。 这种弹性提供了极大的自由,使 PDF 创建者可以自由发挥,并符合各种标准和法规要求。
然而,一旦数据被封装在 PDF 文件中,读取数据就成了挑战。 PDF 的自由形式和复杂特性,常常与企业需要结构化和统一处理大量数据的需求发生冲突。

从发票中提取数据的步骤有哪些?
发票通常以 PDF 格式呈现。 发票本质上是供应商与客户之间,为产品或服务的交易提供的文件。 要从这种文档中提取数据,需要以下步骤:
- 明确你要从发票中提取的数据结构(schema)
- 将发票从图片转换为文本
- 根据你的数据结构从发票文本中提取信息
- 收集已提取的数据

为你的发票数据定义结构(schema)
发票可能来自不同供应商,每个供应商喜欢自定义他们发票的样式。 尽管现实中样式多样,基本内容是一致的:需要包含供应商、客户、发票编号、日期,以及包含数量、描述和金额的项目列表。 定义发票格式的一个好方法是参考你的会计软件,因为最终你很可能会将提取的数据保存到那里。 如果你需要一个能涵盖所有场景的数据格式,推荐使用 schema.org 网站,其为许多场景(包括发票)定义了行业标准格式。 Parseur 定义了发票的默认数据结构,你也可以通过在发票邮箱中重命名字段自定义结构,详细见此处。 一旦数据格式确定好,你就可以将发票从图像转换为文本。
例如,使用 JSON Swagger 格式可以为你的发票定义以下字段:
{
"InvoiceNumber": {
"type": "string",
"description": "发票号"
},
"InvoiceIssueDate": {
"type": "string",
"description": "开票日期"
},
"Items": {
"type": "array",
"description": "发票中的商品列表",
"items": {
"type": "object",
"properties": {
"quantity": {
"type": "number",
"description": "商品数量"
},
"description": {
"type": "string",
"description": "商品描述"
},
"unit_price": {
"type": "number",
"description": "商品单价"
},
"price": {
"type": "number",
"description": "商品总价"
}
}
}
}
}
将你的发票从图片转换为文本

PDF 文件有时包含图片内容。例如,员工可能用手机拍发票照片,保存为 PDF 并发给财务部。 会计人员需要从这些发票中提取数据,并无误录入会计系统。 下一步是用光学字符识别(OCR)技术将图像转为文本。 Tesseract 是最流行的 OCR 方案之一。Tesseract 用 C 和 C++ 编写。要在 Python 中调用 Tesseract,可以用 PyTesseract 这样的绑定。绑定允许你用非原生语言(比如 Python)调用库(如 Tesseract)。 市面上相关系统众多,其效果取决于底层技术和文档扫描质量。 Parseur 会自动检测文档是否为图片并在后台自动将其转换为文本。一旦文档数据变为文本,就可以进行数据提取了。
根据数据结构从发票中提取文本
当你的 PDF 已转换为文本(或支持检索),你可以用 pdftotext Python 库将文本提取出来。 下面是一次将 PDF 提取为文本的代码示例:
import pdftotext
# 加载你的发票
with open("invoice.pdf", "rb") as file_handle:
pdf = pdftotext.PDF(file_handle)
# 遍历所有页面
for page in pdf:
print(page)
将该脚本命名为 convert_pdf_to_text.py 并运行,即可输出发票文本内容。
如果要重定向到文件,可运行:
$ python convert_pdf_to_text.py > invoice.txt
获得文本后,可以采用以下任意组合方式从中提取所需数据:
- 使用正则表达式提取数据。正则表达式功能强大但易碎,遇到格式变化就需调整,且应对表格提取较为困难。
- 利用可视化模板系统,结合动态OCR和区域OCR。这是一种更高级、鲁棒性更强但实现也更复杂的方法。
- 使用机器学习方式。机器学习方案能力强大,但实现最复杂,需要大量样本数据训练,过程耗时,而且结果仍需人工复核。
示例:用 Python 的正则表达式 re 模块从发票中提取发票号码:
import re
# 加载发票文本
with open("invoice.txt", "r") as file_handle:
invoice = file_handle.read()
# 提取发票号
invoice_number = re.search(r"Invoice number: (\w+)", invoice).group(1)
print(invoice_number)
保存脚本为 extract.py 并运行,将在终端输出发票号码:
$ python extract.py
输出结果类似:
INV-1234
注意:该方法仅对格式规范为 Invoice number: INV-1234 的发票有效。
如果发票格式有变化,你需要调整正则表达式。
如果格式类型很多,维护会非常耗时。
Parseur 可以为你处理这些问题。
如果你选择使用正则表达式解析,我们的模板引擎将帮助你管理相关规则, 并且可调用我们多年积累的丰富模板库。 你可以自由选择最佳抽取方式:使用正则表达式、可视化模板(OCR)、机器学习(AI引擎)等组合方式。 甚至可以多种方案联合使用,兼顾灵活性和精确度。 Parseur 还支持提取结果复核和必要修正,这对提升抽取准确率非常关键。
收集已提取的数据
你可以用 Python 批量循环某个文件夹下发票,提取其中的数据。 假设我们提取发票号和总金额,并输出为 CSV 格式:
import os
import re
import pdftotext
# 遍历文件夹下所有 PDF 文件
for filename in os.listdir("invoices/"):
if not filename.endswith(".pdf"):
continue
# 加载发票
with open("invoices/" + filename, "rb") as file_handle:
pdf = pdftotext.PDF(file_handle)
# 打印CSV列标题
print("InvoiceNumber,TotalAmount")
# 遍历所有页面
for page in pdf:
# 提取发票号
invoice_number = re.search(r"Invoice number: (\w+)", page).group(1)
total_amount = re.search(r"Total amount: (\w+)", page).group(1)
print(invoice_number, total_amount, sep=",")
将脚本命名为 extract_to_csv.py 并运行,即可将发票号和总金额输出到终端,
也可以将结果重定向为 CSV 文件,用 Excel 等表格软件查看:
$ python extract_to_csv.py > invoices.csv
在 Parseur 中,当你已完成发票数据提取后,可批量下载表格, 或通过 Webhook 集成、Make、Zapier、 Microsoft Power Automate 等方式直接导出到会计系统,也可通过我们的 API 以 JSON 格式获取数据。
结论
希望本文对你有所帮助! 简而言之,使用 Python 从发票中抽取数据是一个复杂但可行的过程,只要格式统一并有足够的时间调适。 如果你时间有限,不妨利用 Parseur 多年来积累的经验和能力,更快更灵活、更准确地批量提取所有发票数据。
最后更新于






