使用Python从发票中提取数据

要点总结:

  • Python 可以帮助你自动化提取发票数据,但没有“银弹”式的绝对方案
  • Parseur 利用 Python 为你提取发票数据
  • PDF 并非数据文件格式,而是纸质文档的版面表现形式

PDF格式

PDF 格式非常灵活,能够精准呈现如发票等纸质文档,并且对页面设计没有限制。 PDF 源自纸质打印领域,旨在作为打印页面的数字化等效物。 这种弹性提供了极大的自由,使 PDF 创建者可以自由发挥,并符合各种标准和法规要求。

然而,一旦数据被封装在 PDF 文件中,读取数据就成了挑战。 PDF 的自由形式和复杂特性,常常与企业需要结构化和统一处理大量数据的需求发生冲突。

A screen capture of PDF file format layers
PDF file format layers

从发票中提取数据的步骤有哪些?

发票通常以 PDF 格式呈现。 发票本质上是供应商与客户之间,为产品或服务的交易提供的文件。 要从这种文档中提取数据,需要以下步骤:

  1. 明确你要从发票中提取的数据结构(schema)
  2. 将发票从图片转换为文本
  3. 根据你的数据结构从发票文本中提取信息
  4. 收集已提取的数据

A screen capture of Invoice data extraction process
Invoice data extraction process

为你的发票数据定义结构(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": "商品总价"
                }
            }
        }
    }
}

将你的发票从图片转换为文本

A screen capture of an invoice taken from a smartphone
Picture of an invoice taken from a smartphone

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 可以为你处理这些问题。

注册您的免费账户
使用 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 集成MakeZapierMicrosoft Power Automate 等方式直接导出到会计系统,也可通过我们的 API 以 JSON 格式获取数据。

结论

希望本文对你有所帮助! 简而言之,使用 Python 从发票中抽取数据是一个复杂但可行的过程,只要格式统一并有足够的时间调适。 如果你时间有限,不妨利用 Parseur 多年来积累的经验和能力,更快更灵活、更准确地批量提取所有发票数据。

最后更新于

基于AI的数据提取软件。
立即开始使用Parseur。

自动提取电子邮件、PDF和电子表格中的文本。
节省数百小时的手动工作。
体验AI赋能的工作自动化。

Parseur rated 5/5 on Capterra
Parseur.com has the highest adoption on G2
Parseur.com has the happiest users badge on Crozdesk
Parseur rated 5/5 on GetApp
Parseur rated 4.5/5 on Trustpilot