基于Python与OCR的票据图片批量数据提取实战
面对大量发票或承兑单据的图片,手动录入效率极低。本文演示如何使用Python脚本读取图片、按区域裁剪、调用OCR引擎识别关键字段,并将包含中文大写金额的票据数据统一清洗后导出为Excel表格,适用于财务对账、单据归档等场景。
需求分析与环境配置
该方案的核心目标是:将指定文件夹内的票据图片逐张打开,利用图像坐标截取需要提取的文本区域,调用OCR工具进行识别,对中文大写金额进行数值化转换,最后将结果按固定表头写入Excel文件。操作前需确保以下基础条件已就绪:
- 系统组件:安装
Tesseract-OCR与ImageMagick,用于底层图像解析与字符识别支撑。 - 运行环境:
Python 3.7+。 - 核心库:
PIL(图像处理)、io与os(文件流遍历)、pyocr(通用OCR封装)、cnocr(中文高精度识别)、xlwt(Excel写入)。 - 模型初始化:
CnOcr首次运行会自动下载中文预训练模型,需保持网络畅通。
第1步:编写中文大写金额转换逻辑
票据中的金额常以汉字大写形式呈现(如“贰拾万元整”),直接导入表格不利于后续统计。需在预处理阶段将其转换为阿拉伯整数,便于Excel计算与筛选。
def chineseNumber2Int(strNum: str):
result = 0
temp = 1 # 存放一个单位的基数,如十万
count = 0 # 记录连续出现的单位数
cnArr = ['壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
chArr = ['拾', '佰', '仟', '万', '亿']
for char in strNum:
base_found = False
for val_idx, digit in enumerate(cnArr):
if char == digit:
if count != 0:
result += temp
count = 0
temp = val_idx + 1
base_found = True
break
if not base_found:
for unit_idx, unit in enumerate(chArr):
if char == unit:
multipliers = [10, 100, 1000, 10000, 100000000]
temp *= multipliers[unit_idx]
count += 1
result += temp
return result
输入任意标准大写格式字符串,该函数即可返回对应的整型数值。例如传入“贰拾万元整”将输出 200000,有效简化了表格后期的数据清洗流程。
第2步:按固定坐标裁剪与OCR识别
对于版面固定的票据,最稳定且高效的方式是预先标定各字段的像素坐标,利用 PIL.Image.crop() 精确切分目标区域,再分别交由适合的OCR引擎处理。日期与纯数字区域通常适合传统OCR,中文密集区建议使用 CnOcr。
可通过系统自带画图软件打开测试图片,拖动鼠标查看左下角状态栏的实时坐标,据此划定左上角 (left, top) 与右下角 (right, bottom) 边界。


字段提取函数结构统一,以下为其中两个典型示例。实际项目中可将坐标、引擎调用封装为配置字典,按需循环调用:
def extract_date(new_img, tool):
# 出票日期区域
cropped = new_img.crop((80, 143, 162, 162))
return str(tool.image_to_string(cropped))
def extract_amount(new_img, ocr_engine):
# 金额区域
cropped = new_img.crop((224, 355, 585, 380))
raw_text = "".join(ocr_engine.ocr("temp_crop.png")[0])
return chineseNumber2Int(raw_text)第3步:批量遍历与Excel结构化导出
完成单个文件的处理逻辑后,进入批量执行环节。使用 os.walk 扫描目标文件夹,依次读取二进制流转为PIL图像对象,执行上述提取函数,并按行列写入工作表。
注意:原草稿示例中将 book.save() 放在了循环体内,会导致频繁覆盖或产生冗余文件。正确做法是在循环外统一保存,且表头仅写入一次。
import os
from PIL import Image as PI
import io
from cnocr import CnOcr
import pyocr
import xlwt
# 1. 初始化引擎
ocr_cn = CnOcr()
tool_tess = pyocr.get_available_tools()[0]
file_dir = 'img'
workbook = xlwt.Workbook(encoding='utf-8')
sheet = workbook.add_sheet('票据明细', cell_overwrite_ok=True)
# 2. 写入表头(循环外仅执行一次)
headers = ('年份','出票日期','金额','出票人','付款行全称','汇票到期日','备注')
for col_idx, h in enumerate(headers):
sheet.write(0, col_idx, h)
count = 1
# 3. 遍历处理所有图片
for root, _, filenames in os.walk(file_dir):
for fname in filenames:
img_path = os.path.join(root, fname)
with open(img_path, 'rb') as f:
pil_img = PI.open(io.BytesIO(f.read()))
try:
dt = extract_date(pil_img, tool_tess)
amt = extract_amount(pil_img, ocr_cn)
# 其余字段调用对应函数...
sheet.write(count, 0, dt[:4]) # 年份
sheet.write(count, 1, dt[5:]) # 月日
sheet.write(count, 2, amt) # 数值化金额
# sheet.write(count, 3, txt_drawer)
# sheet.write(count, 4, txt_payer)
# ...其他列
count += 1
except Exception as e:
print(f"跳过异常文件 {fname}: {e}")
# 4. 统一保存(放在最终出口)
workbook.save('票据数据汇总.xls')常见报错与参数调整
- 识别结果为空或乱码:裁剪区域未完全覆盖文字,或背景噪声过重。需微调
crop坐标,并在识别前增加灰度二值化处理image.convert('L')。 - CnOcr模型缺失报错:首次运行会在用户目录下创建
.cache/cnocr并下载权重。若服务器无外网,需手动下载模型包并设置环境变量CNOCR_MODEL_PATH。 - 横竖版或分辨率不一致:硬编码坐标强依赖原始图片尺寸。若票据存在缩放,应引入相对比例换算(如将坐标乘以
actual_width / 1080),或改用版面分析算法动态定位。
总结
本方案通过“坐标裁剪+双引擎识别+大写转数字”的组合策略,实现了固定格式票据数据的自动化提取与表格化输出。脚本可直接嵌入定时任务或财务SOP流程中,大幅降低人工录入成本。在实际部署前,请务必先用少量样本验证坐标精度与金额转换的正确性。以上就是基于Python与OCR的票据图片批量数据提取的详细内容,更多关于Python票据识别与自动化办公的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









