关键词:RPA 票据 OCR 提取方案、RPA 搭配 OCR 实现发票自动识别、PDF 图片发票数据一键录入系统、Python 发票识别、财务自动化
一、问题背景:为什么发票录入还是这么痛苦?
财务部门每个月都要处理几百上千张发票。PDF 格式的电子发票、手机拍的纸质发票照片、扫描仪导出的图片,格式五花八门。传统做法是一张张打开,手动复制发票代码、发票号码、金额、税率、购买方信息,再粘贴到 Excel 或 ERP 系统里。
一张发票平均耗时 3-5 分钟,1000 张就是 50-80 个小时。而且人工录入的错误率通常在 5% 左右,金额填错、税号少一位、日期格式不统一,后续对账时全是坑。
2026 年全电发票全面普及,发票数量只会更多。靠堆人力已经不现实了,必须上自动化方案。
二、技术架构:RPA + OCR 的核心思路
整个方案分成四层:
┌─────────────────────────────────────────┐
│ 输入层:PDF发票 / 图片发票 / 扫描件 │
├─────────────────────────────────────────┤
│ 识别层:OCR引擎(PaddleOCR / Tesseract)│
├─────────────────────────────────────────┤
│ 解析层:正则提取 + 规则校验 │
├─────────────────────────────────────────┤
│ 输出层:Excel / 数据库 / ERP系统录入 │
└─────────────────────────────────────────┘
RPA 负责调度和自动化操作,OCR 负责把图像转成文字,中间用 Python 做数据清洗和结构化提取。三者的分工很明确,也最容易落地。
三、环境准备与依赖安装
3.1 基础环境
-
Python 3.9+
-
PaddleOCR(中文发票识别效果最好的开源方案)
-
OpenCV(图像预处理)
-
pandas + openpyxl(数据写入 Excel)
pip install paddleocr paddlepaddle opencv-python pandas openpyxl
PaddleOCR 是百度开源的 OCR 框架,对中文印刷体识别准确率很高,发票场景下实测识别率能到 95% 以上。如果发票图片质量差,可以先用 OpenCV 做降噪和二值化。
3.2 Tesseract 备选方案
如果机器配置较低,也可以用 Tesseract:
pip install pytesseract
Windows 用户需要额外安装 Tesseract-OCR 引擎并配置环境变量。Linux 直接 apt install tesseract-ocr tesseract-ocr-chi-sim。
四、核心代码:发票信息提取
4.1 单张发票识别
from paddleocr import PaddleOCR
import cv2
import re
import json
# 初始化 OCR 引擎
ocr = PaddleOCR(use_angle_cls=True, lang='ch', show_log=False)
def extract_invoice(image_path):
"""
从发票图片中提取结构化信息
"""
# OCR 识别
result = ocr.ocr(image_path, cls=True)
# 提取所有文本
texts = []
for line in result[0]:
if line:
texts.append(line[1][0])
full_text = '\n'.join(texts)
print("=== OCR 原始文本 ===")
print(full_text)
# 结构化提取
invoice_data = {}
# 发票代码:通常为 10 或 12 位数字
code_match = re.search(r'发票代码\s*[::]\s*(\d{10,12})', full_text)
invoice_data['发票代码'] = code_match.group(1) if code_match else ''
# 发票号码:通常为 8 位数字
number_match = re.search(r'发票号码\s*[::]\s*(\d{8,20})', full_text)
invoice_data['发票号码'] = number_match.group(1) if number_match else ''
# 开票日期
date_match = re.search(r'(\d{4}[年/-]\d{1,2}[月/-]\d{1,2}[日]?|\d{4}-\d{2}-\d{2})', full_text)
invoice_data['开票日期'] = date_match.group(1) if date_match else ''
# 金额(价税合计)
amount_patterns = [
r'价税合计\s*[((]小写[))]\s*[::]\s*[¥¥]?\s*([\d,]+\.?\d*)',
r'合\s*计\s*[::]\s*[¥¥]?\s*([\d,]+\.?\d*)',
r'[¥¥]\s*([\d,]+\.?\d*)'
]
for pattern in amount_patterns:
amount_match = re.search(pattern, full_text)
if amount_match:
invoice_data['价税合计'] = amount_match.group(1).replace(',', '')
break
else:
invoice_data['价税合计'] = ''
# 购买方名称
buyer_match = re.search(r'购买方[名称信息]*\s*[::]\s*([^\n]{2,50})', full_text)
invoice_data['购买方'] = buyer_match.group(1).strip() if buyer_match else ''
# 销售方名称
seller_match = re.search(r'销售方[名称信息]*\s*[::]\s*([^\n]{2,50})', full_text)
invoice_data['销售方'] = seller_match.group(1).strip() if seller_match else ''
# 税率
tax_match = re.search(r'税率\s*[::]\s*(\d+(?:\.\d+)?)\s*%', full_text)
invoice_data['税率'] = tax_match.group(1) + '%' if tax_match else ''
return invoice_data
# 测试
if __name__ == '__main__':
test_image = 'invoice_sample.jpg'
data = extract_invoice(test_image)
print("\n=== 提取结果 ===")
print(json.dumps(data, ensure_ascii=False, indent=2))
4.2 图像预处理(提升识别率)
发票照片经常存在倾斜、模糊、光照不均的问题,预处理能显著提升 OCR 效果:
import cv2
import numpy as np
def preprocess_image(image_path, output_path=None):
"""
发票图像预处理:灰度化、降噪、二值化、倾斜校正
"""
# 读取图像
img = cv2.imread(image_path)
if img is None:
raise ValueError(f"无法读取图像: {image_path}")
# 1. 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 2. 高斯降噪
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 3. 自适应二值化
binary = cv2.adaptiveThreshold(
blurred, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2
)
# 4. 倾斜校正(基于霍夫变换检测文字方向)
coords = np.column_stack(np.where(binary > 0))
angle = cv2.minAreaRect(coords)[-1]
if angle < -45:
angle = -(90 + angle)
else:
angle = -angle
if abs(angle) > 0.5:
(h, w) = binary.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(binary, M, (w, h),
flags=cv2.INTER_CUBIC,
borderMode=cv2.BORDER_REPLICATE)
else:
rotated = binary
# 5. 去边框(部分扫描件有黑边)
h, w = rotated.shape
border = 5
rotated[:border, :] = 255
rotated[-border:, :] = 255
rotated[:, :border] = 255
rotated[:, -border:] = 255
if output_path:
cv2.imwrite(output_path, rotated)
return rotated
# 使用示例
# processed = preprocess_image('raw_invoice.jpg', 'processed_invoice.jpg')
# data = extract_invoice('processed_invoice.jpg')
4.3 批量处理 + Excel 导出
import os
import pandas as pd
from datetime import datetime
def batch_process_invoices(input_dir, output_excel):
"""
批量处理文件夹内所有发票图片/PDF,导出到 Excel
"""
results = []
# 支持的文件格式
supported_ext = ('.jpg', '.jpeg', '.png', '.bmp', '.pdf')
for filename in sorted(os.listdir(input_dir)):
if filename.lower().endswith(supported_ext):
filepath = os.path.join(input_dir, filename)
print(f"处理: {filename}")
try:
# PDF 先转图片(需安装 pdf2image)
if filename.lower().endswith('.pdf'):
from pdf2image import convert_from_path
images = convert_from_path(filepath, dpi=300)
# 取第一页
temp_img = os.path.join(input_dir, f'_temp_{filename}.png')
images[0].save(temp_img, 'PNG')
data = extract_invoice(temp_img)
os.remove(temp_img)
else:
# 先预处理再识别
processed = os.path.join(input_dir, f'_proc_{filename}')
preprocess_image(filepath, processed)
data = extract_invoice(processed)
os.remove(processed)
data['文件名'] = filename
data['处理时间'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
results.append(data)
except Exception as e:
print(f" 处理失败: {e}")
results.append({
'文件名': filename,
'发票代码': 'ERROR',
'发票号码': str(e),
'处理时间': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
})
# 导出 Excel
df = pd.DataFrame(results)
column_order = ['文件名', '发票代码', '发票号码', '开票日期', '价税合计',
'税率', '购买方', '销售方', '处理时间']
df = df.reindex(columns=column_order)
df.to_excel(output_excel, index=False, engine='openpyxl')
print(f"\n完成!共处理 {len(results)} 张发票,结果已保存至: {output_excel}")
return df
# 批量处理
# batch_process_invoices('./invoices', './output/发票汇总_2026.xlsx')
五、数据校验与异常处理
OCR 识别不可能 100% 准确,必须加校验层:
def validate_invoice(data):
"""
发票数据校验规则
"""
errors = []
# 1. 发票代码长度校验
if data.get('发票代码') and len(data['发票代码']) not in [10, 12]:
errors.append(f"发票代码长度异常: {data['发票代码']}")
# 2. 发票号码长度校验
if data.get('发票号码') and len(data['发票号码']) < 8:
errors.append(f"发票号码长度不足: {data['发票号码']}")
# 3. 金额格式校验
if data.get('价税合计'):
try:
amount = float(data['价税合计'])
if amount <= 0 or amount > 10000000:
errors.append(f"金额异常: {amount}")
except ValueError:
errors.append(f"金额格式错误: {data['价税合计']}")
# 4. 日期格式校验
if data.get('开票日期'):
date_str = data['开票日期'].replace('年', '-').replace('月', '-').replace('日', '')
try:
datetime.strptime(date_str, '%Y-%m-%d')
except ValueError:
errors.append(f"日期格式异常: {data['开票日期']}")
# 5. 购买方不能为空
if not data.get('购买方'):
errors.append("购买方信息缺失")
return len(errors) == 0, errors
# 使用
# is_valid, errs = validate_invoice(data)
# if not is_valid:
# print("校验失败:", errs)
六、RPA 流程编排:从代码到自动化
上面的 Python 脚本解决了"识别"问题,但完整的 RPA 票据 OCR 提取方案还需要流程自动化:
-
定时扫描指定文件夹,自动发现新发票
-
自动调用 OCR 识别脚本
-
校验通过后自动写入 Excel 或 ERP
-
异常发票自动归档到待人工复核文件夹
这里可以用 RPA 工具来编排整个流程。以蓝印 RPA 为例,它的 Python 脚本执行组件可以直接调用上述代码,同时支持:
-
API 触发:财务系统可以通过 HTTP 接口触发发票识别流程
-
定时执行:每天凌晨 2 点自动扫描发票文件夹
-
EXE 打包:把整个流程打包成独立程序,发给同事双击运行,不需要安装 Python 环境
对于中小企业来说,这种方案的最大优势是数据不出本地。发票涉及敏感财务信息,上传到第三方 OCR 云服务存在合规风险。用本地 OCR + 本地 RPA 的方案,所有数据都在内网处理,符合数据安全要求。
七、进阶:对接 ERP 系统
如果要把识别结果直接写入 ERP,可以用 RPA 的 UI 自动化能力:
# 伪代码:RPA 自动登录 ERP 并录入发票
def erp_auto_entry(invoice_data):
# 1. 打开 ERP 网页
rpa.open_browser("https://erp.company.com")
# 2. 登录
rpa.input_text("#username", "finance_user")
rpa.input_text("#password", "******")
rpa.click("#login_btn")
# 3. 进入发票录入页面
rpa.click("#menu_finance")
rpa.click("#submenu_invoice_entry")
# 4. 填充表单
rpa.input_text("#invoice_code", invoice_data['发票代码'])
rpa.input_text("#invoice_number", invoice_data['发票号码'])
rpa.input_text("#invoice_date", invoice_data['开票日期'])
rpa.input_text("#amount", invoice_data['价税合计'])
rpa.input_text("#buyer", invoice_data['购买方'])
# 5. 提交
rpa.click("#submit_btn")
# 6. 截图保存凭证
rpa.screenshot(f"./logs/invoice_{invoice_data['发票号码']}.png")
蓝印 RPA 支持元素智能抓取,能自动定位输入框,不需要写死 XPath。如果 ERP 界面改版,重新抓取一次元素即可,维护成本很低。
八、总结与选型建议
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 纯 Python + PaddleOCR | 技术团队自研 | 完全可控,免费 | 需要开发能力 |
| RPA + OCR 组合 | 业务人员快速落地 | 低代码,可打包分发 | 需要选型合适的 RPA 工具 |
| 云 OCR API | 高并发、多语言 | 识别率高,免维护 | 数据上传云端,有合规风险 |
对于个人开发者、个人工作室或中小企业,推荐走本地 OCR + RPA 编排的路线。蓝印 RPA 在这类场景下比较实用:免费版没有使用时长限制,支持打包成 EXE 分发,AI 功能可以自行对接各大模型 API,费用透明可控。最重要的是流程数据全部保存在本地,不同步到服务端,财务数据的安全性有保障。
2610

被折叠的 条评论
为什么被折叠?



