影刀RPA 发票报销自动化:识别校验与审批流
影刀RPA 发票报销自动化识别校验与审批流作者林焱 | 适用人群影刀RPA新手 | 难度★★★☆☆一、什么情况用这个财务或者经常报销的同事每个月要处理几十上百张发票——核对发票信息、查重防止重复报销、录入系统、提交审批。一张一张手动处理眼睛看花还容易出错。用影刀RPA读取发票图片/PDF → OCR识别关键字段 → 自动查重 → 写入报销系统 → 提交审批。你只需要把发票丢进文件夹剩下的机器人搞定。实际场景月度费用报销、差旅发票整理、供应商发票校验、发票台账自动维护。这篇文章能解决的问题OCR识别发票上的关键信息发票号码、金额、日期、税号自动查重——防止同一张发票重复报销发票信息自动录入Excel台账对接OA系统提交报销审批二、怎么做2.1 环境准备影刀安装目录\python\python.exe-mpipinstallcnocr PillowCNOCR是专门优化中文的OCR库对发票上的中文字体识别效果好。2.2 影刀主流程┌──────────────────────────────────────────────┐ │ ① 【监控文件夹】 │ │ 监控「待处理发票」文件夹有新文件触发 │ │ ↓ │ │ ② 【执行Python代码】 │ │ OCR识别发票图片提取关键信息 │ │ ↓ │ │ ③ 【执行Python代码】 │ │ 发票查重 信息校验 │ │ ↓ │ │ ④ 【读取Excel】 │ │ 检查发票台账是否已有此发票 │ │ ↓ │ │ ⑤ 【写入Excel】 │ │ 将校验通过的发票写入台账 │ │ ↓ │ │ ⑥ 【条件判断】 │ │ 需要审批→ ⑦发送审批请求 │ └──────────────────────────────────────────────┘2.3 OCR识别发票步骤②提取发票信息fromcnocrimportCnOcrimportreimportjsonimportos# 初始化OCR只需初始化一次ocrCnOcr()defextract_invoice_info(image_path):从发票图片中提取关键信息# OCR识别resultocr.ocr(image_path)# 拼接所有识别出的文字full_text\n.join([item[text]foriteminresult])info{file_path:image_path,raw_text:full_text,}# 正则提取关键字段 # 1. 发票号码通常8位或10位数字invoice_no_matchre.search(r发票号码[:\s]*(\d{8,10}),full_text)ifinvoice_no_match:info[invoice_no]invoice_no_match.group(1)# 2. 发票金额找「合计金额」后面的数字amount_matchre.search(r合[计計][金金额][:\s]*[¥]?\s*([\d,]\.?\d{0,2}),full_text)ifamount_match:info[amount]amount_match.group(1).replace(,,)# 3. 开票日期date_matchre.search(r开票日期[:\s]*(\d{4}[-/年]\d{1,2}[-/月]\d{1,2}),full_text)ifdate_match:info[invoice_date]date_match.group(1)# 4. 销售方名称seller_matchre.search(r销售方名[称稱][:\s]*([^\n]{4,30}),full_text)ifseller_match:info[seller_name]seller_match.group(1).strip()# 5. 购买方税号15-20位数字字母组合tax_id_matchre.search(r纳税人识别号[:\s]*([A-Za-z0-9]{15,20}),full_text)iftax_id_match:info[tax_id]tax_id_match.group(1)returninfo# 批量处理 INVOICE_FOLDERrD:\发票\待处理results[]forfilenameinos.listdir(INVOICE_FOLDER):iffilename.lower().endswith((.png,.jpg,.jpeg,.pdf)):filepathos.path.join(INVOICE_FOLDER,filename)print(f处理{filename})infoextract_invoice_info(filepath)results.append(info)outputjson.dumps(results,ensure_asciiFalse)print(f共处理{len(results)}张发票)2.4 查重 校验步骤③④防止重复报销importjsonfromdatetimeimportdatetime invoicesjson.loads(ocr_results)# 从步骤②传入# 校验规则 defvalidate_invoice(invoice):校验发票信息完整性errors[]ifnotinvoice.get(invoice_no):errors.append(未识别到发票号码)ifnotinvoice.get(amount):errors.append(未识别到发票金额)ifnotinvoice.get(invoice_date):errors.append(未识别到开票日期)eliffloat(invoice.get(amount,0))0:errors.append(发票金额无效)returnerrors# 查重 # 从发票台账Excel中读取已有的发票号码列表# 在影刀中用【读取Excel】获取 existing_numbersexisting_numbersset([str(n)forninexisting_invoice_numbers])valid_invoices[]duplicate_invoices[]error_invoices[]forinvininvoices:# 校验errorsvalidate_invoice(inv)iferrors:inv[errors]errors error_invoices.append(inv)continue# 查重ifinv.get(invoice_no)inexisting_numbers:duplicate_invoices.append(inv)continue# 通过inv[processed_time]datetime.now().strftime(%Y-%m-%d %H:%M:%S)valid_invoices.append(inv)summary{total:len(invoices),valid:len(valid_invoices),duplicate:len(duplicate_invoices),error:len(error_invoices),valid_list:valid_invoices,duplicate_list:duplicate_invoices,error_list:error_invoices,}outputjson.dumps(summary,ensure_asciiFalse)print(f校验完成有效{len(valid_invoices)}重复{len(duplicate_invoices)}异常{len(error_invoices)})2.5 写入台账步骤⑤Excel记录在影刀中【打开Excel文件】→ D:\发票\发票台账.xlsx 【遍历列表】→ valid_list中的每条记录 【写入行】 列Ainvoice_no发票号码 列Bamount金额 列Cinvoice_date开票日期 列Dseller_name销售方 列Efile_path图片路径 列Fprocessed_time处理时间 列Gstatus状态 待审批 【保存并关闭】 # 将原始发票图片移动到「已处理」文件夹 【移动文件】 源文件file_path 目标文件夹D:\发票\已处理\2.6 提交审批步骤⑥⑦OA系统审批如果你们公司有OA系统泛微/致远/钉钉OA等【打开网页】→ OA系统报销页面 【填写】→ 发票号码、金额、日期等字段 【上传附件】→ 发票图片 【点击】→ 提交按钮如果用的是飞书/钉钉审批# 飞书审批API示例importrequestsdefsubmit_feishu_approval(invoice_info):提交飞书审批urlhttps://open.feishu.cn/open-apis/approval/v4/instancesheaders{Authorization:fBearer{FEISHU_TOKEN},Content-Type:application/json,}payload{approval_code:报销审批的approval_code,user_id:提交人ID,form:json.dumps([{id:widget_invoice_no,type:input,value:invoice_info[invoice_no]},{id:widget_amount,type:input,value:invoice_info[amount]},{id:widget_date,type:input,value:invoice_info[invoice_date]},]),}responserequests.post(url,headersheaders,jsonpayload,timeout10)returnresponse.json()三、有什么坑坑1OCR对发票图片质量要求高拍照模糊、倾斜、有遮挡的发票OCR识别率会明显下降。提升识别率的方法fromPILimportImage,ImageEnhancedefpreprocess_image(image_path):预处理发票图片imgImage.open(image_path)# 1. 增强对比度让文字更清晰enhancerImageEnhance.Contrast(img)imgenhancer.enhance(1.5)# 2. 增强锐度enhancerImageEnhance.Sharpness(img)imgenhancer.enhance(2.0)# 3. 转为灰度加速识别imgimg.convert(L)preprocessed_pathimage_path.replace(.,_preprocessed.)img.save(preprocessed_path)returnpreprocessed_path坑2不同发票格式正则难写增值税专票、普票、电子发票的版面不一样固定的正则可能匹配不准。解决思路不追求100%准确对识别失败的发一个「需人工核对」的标记让人工介入。机器能搞定80%剩下20%留给人。坑3PDF发票的OCRPDF发票需要先转图片再OCR# 需要安装 pdf2image# pip install pdf2imagefrompdf2imageimportconvert_from_pathdefpdf_to_images(pdf_path):将PDF发票转为图片列表imagesconvert_from_path(pdf_path,dpi200)image_paths[]fori,imginenumerate(images):pathpdf_path.replace(.pdf,f_page{i1}.png)img.save(path,PNG)image_paths.append(path)returnimage_paths坑4发票查重依赖台账完整性如果台账Excel被人手动删除过记录查重就会漏掉。建议台账文件设置权限只允许影刀写入人工只读或者用数据库存储。坑5报销金额小数点问题OCR可能把「1280.00」识别成「1280 00」少了小数点。正则提取金额时要做容错# 金额清洗函数defclean_amount(raw_amount):清洗OCR识别的金额# 移除中文逗号、空格cleanedraw_amount.replace(,).replace( ,).replace(,).replace(¥,)# 处理可能缺失的小数点if.notincleanedandlen(cleaned)3:# 假设最后两位是小数cleanedcleaned[:-2].cleaned[-2:]try:returnf{float(cleaned):.2f}exceptValueError:returnraw_amount总结影刀做发票报销OCR是关键环节。CNOCR对中文发票识别效果好但需要预处理图片提升准确率。查重用台账Excel做简单去重校验用正则提取关键字段。不要追求100%自动化留一个人工复核的出口。