Python 批量自动提取、整理 PDF 发票
随着数字化的普及,越来越多的发票以 PDF 格式进行存储,这给企业的账务管理和数据统计带来了方便,但也带来了一定的问题:如何快速、准确地从大量的 PDF 发票中提取所需的数据?本文将介绍使用 Python 对 PDF 发票进行批量自动提取和整理的方法。
1. 环境准备
为了方便操作 PDF 文件,我们需要安装 Python 的 PDF 处理库 PyPDF2 和数据处理库 Pandas。可以通过以下命令进行安装:
pip install PyPDF2 pandas
2. 提取 PDF 发票数据
使用 PyPDF2 库可以非常方便地从 PDF 文件中提取文本数据。我们可以将 PDF 中需要提取的数据抽象为一张表格,每行代表一张发票,每列代表发票的一种信息,例如:发票号码、开票日期、销售方名称、购买方名称、商品名称、商品数量、商品单价等。
我们可以定义一个函数,将 PDF 文件的每一页转成文本,并通过正则表达式进行匹配,提取所需的数据。具体代码如下:
import re
from io import BytesIO
from typing import List
import pandas as pd
from PyPDF2 import PdfFileReader
def extract_invoice_data(pdf_bytes: bytes, start_page: int,
end_page: int) -> pd.DataFrame:
pages = []
with BytesIO(pdf_bytes) as f:
pdf = PdfFileReader(f)
for i in range(start_page - 1, end_page):
page = pdf.getPage(i)
text = page.extractText()
pages.append(text)
data = []
for page in pages:
regex = r'发票号码[::]\s*(\S+).*?'
regex += r'开票日期[::]\s*(\S+).*?'
regex += r'销售方名称[::]\s*((.*\n)+)?.*?'
regex += r'购买方名称[::]\s*((.*\n)+)?.*?'
regex += r'商品名称[::]\s*((.*\n)+)?.*?'
regex += r'商品数量[::]\s*(\S+).*?'
regex += r'商品单价[::]\s*(\S+)'
matches = re.findall(regex, page, re.S)
for match in matches:
invoice_no, invoice_date, seller, buyer, item_name, item_qty, item_price = match
data.append({
'发票号码': invoice_no.strip().replace('\n', ''),
'开票日期': invoice_date.strip(),
'销售方名称': seller.strip().replace('\n', '') if seller else '',
'购买方名称': buyer.strip().replace('\n', '') if buyer else '',
'商品名称': item_name.strip().replace('\n', '') if item_name else '',
'商品数量': item_qty.strip(),
'商品单价': item_price.strip()})
df = pd.DataFrame(data)
return df
以上代码使用正则表达式对 PDF 中的文本进行匹配,提取发票号码、开票日期、销售方名称、购买方名称、商品名称、商品数量、商品单价等信息,并将其保存到 DataFrame 中。这里需要注意的是,PDF 文件中的文本可能是以多行呈现的,因此我们需要对多行文本进行处理。为了方便数据的后续处理和存储,我们将发票信息保存到 DataFrame 中。
3. 批量处理 PDF 发票
对于大规模的 PDF 发票数据,我们需要批量处理。为了方便起见,我们可以将每个 PDF 文件看成一个批次,将多个 PDF 文件作为多个批次进行处理。
具体而言,我们可以将每个 PDF 文件读入内存,调用 extract_invoice_data 函数提取发票信息,并将结果保存到磁盘文件中。以下是实现代码:
import os
def batch_process_pdfs(pdf_dir: str, start_page: int, end_page: int,
out_dir: str) -> None:
if not os.path.exists(out_dir):
os.makedirs(out_dir)
for pdf_file in os.listdir(pdf_dir):
file_path = os.path.join(pdf_dir, pdf_file)
if os.path.isfile(file_path) and file_path.endswith('.pdf'):
with open(file_path, 'rb') as f:
pdf_bytes = f.read()
df = extract_invoice_data(pdf_bytes, start_page, end_page)
out_file_name = pdf_file.replace('.pdf', '.csv')
out_file_path = os.path.join(out_dir, out_file_name)
df.to_csv(out_file_path, index=None)
以上代码将 PDF 文件的后缀名替换成 CSV,将每个文件的发票信息保存到同名的 CSV 文件中。
4. 数据整理和清洗
对于提取出来的数据,很可能存在一些缺失值和噪声,这些需要进行清洗和整理。我们可以通过 Pandas 库的一些函数对数据进行操作,例如:fillna 函数填充缺失值,drop_duplicates 函数去掉重复的记录,dropna 函数去掉缺失值等。以下是一个简单的数据清洗和整理代码示例:
import pandas as pd
def clean_dataframe(df: pd.DataFrame) -> pd.DataFrame:
# 去掉空白行
df = df.dropna(how='all')
# 去掉重复行
df = df.drop_duplicates(subset=['发票号码'], keep='last')
# 填充缺失值
df = df.fillna('')
# 按照发票号码排序
df = df.sort_values(by='发票号码')
return df
以上代码对 DataFrame 进行了去重、填充和排序等操作,并将处理后的 DataFrame 返回。
5. 结语
以上就是使用 Python 对 PDF 发票进行批量自动提取和整理的方法。这种方法可以为企业的数据统计和管理带来很大的方便,但也需要注意 PDF 文件本身的格式,确保文本内容可以被正确抽取。