Python实现发票自动校核微信机器人的方法

制作初衷:

  • 外地开了票到公司后发现信息有错误,无法报销;
  • 公司的行政和财务经常在工作日被问及公司开票信息,影响心情和工作;
  • 引入相应的专业APP来解决发票问题对于一般公司成本较高;
  • 看到朋友孟要早睡写过脚本来解决这个问题,但因为公司场景不相同,无法复用,所以新写了一个

本代码使用简单的封装方法,并做了比较走心的注释,希望能给初学Python的小伙伴提供一些灵感,也能让有实际需求的人可以快速修改、使用。

源码地址:https://github.com/yc2code/WechatInvoiceParser

P.S. 工具基于微信网页版,因为微信官方对于账号有限制,新建的账号可能无法使用,会报:KeyError: 'pass_ticket',如图:

所以工具只能使用注册时间较早的账号

发票自动校核微信机器人代码部分

1. 工具文件 – Utils
包含三个部分:发票校核类 Invoice、解析数据类 DataParser 和推送日志类 Pushover

  • Invoice 调用的百度API,上传图片信息,得到解析数据;
  • DataParser 对得到的解析数据进行整理,得到发送给用户的信息;
  • Pushover 出现调用问题时,第一时间相关信息推送到维护者的设备上。
# -*- coding: utf-8 -*-
# Utils.py
import base64
import csv
import os
import time
import requests
from Config import config
class Invoice:
 """
 发票识别类
 使用百度发票识别API,免费使用
 官方地址 https://ai.baidu.com/docs#/OCR-API/5099e085
 其它功能及配置请移步官网
 """
 @staticmethod
 def get_pic_content(image_path):
  """
  方法--打开图片
  以二进制格式打开
  """
  with open(image_path, 'rb') as pic:
   return pic.read()
 @staticmethod
 def parse_invoice(image_binary):
  """
  方法--识别图片
  调用百度接口,返回识别后的发票数据
  以下内容基本根据API调用的要求所写,无需纠结
  各类报错码在官网文档可查
  百度API注册及使用教程:http://ai.baidu.com/forum/topic/show/867951
  """
  # 识别质量可选high及normal
  # normal(默认配置)对应普通精度模型,识别速度较快,在四要素的准确率上和high模型保持一致,
  # high对应高精度识别模型,相应的时延会增加,因为超时导致失败的情况也会增加(错误码282000)
  access_token = "你的access_token"
  api_url = f"https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice?access_token={access_token}"
  quality = "high"
  header = {"Content-Type": "application/x-www-form-urlencoded"}
  # 图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M,
  # 最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式
  image_data = base64.b64encode(image_binary)
  try:
   data = {"accuracy": quality, "image": image_data}
   response = requests.post(api_url, data=data, headers=header)
   if response.status_code != 200:
    print(time.ctime()[:-5], "Failed to get info")
    return None
   else:
    result = response.json()["words_result"]
    invoice_data = {
     '检索日期': '-'.join(time.ctime().split()[1:3]),
     '发票代码': result['InvoiceCode'],
     '发票号码': result['InvoiceNum'],
     '开票日期': result['InvoiceDate'],
     '合计金额': result['TotalAmount'],
     '价税合计': result['AmountInFiguers'],
     '销售方名称': result['SellerName'],
     '销售方税号': result['SellerRegisterNum'],
     '购方名称': result['PurchaserName'],
     '购方税号': result['PurchaserRegisterNum'],
     "发票类型": result["InvoiceType"]
    }
    return invoice_data
  except:
   message = "发票识别API调用出现错误"
   Pushover.push_message(message)
   return None
  finally:
   print(time.ctime()[:-5], "产生一次了调用")
 @staticmethod
 def save_to_csv(invoice_data):
  """
  方法--日志保存
  将识别记录写入文件夹下work_log.csv文件
  若无此文件则自动创建并写入表头
  """
  if "work_log.csv" not in os.listdir():
   not_found = True
  else:
   not_found = False
  with open('./work_log.csv', 'a+') as file:
   writer = csv.writer(file)
   if not_found:
    writer.writerow(invoice_data.keys())
   writer.writerow(invoice_data.values())
 @staticmethod
 def run(image_path):
  """
  主方法
  解析完成返回信息,否则返回None
  """
  image_binary = Invoice.get_pic_content(image_path)
  invoice_data = Invoice.parse_invoice(image_binary)
  if invoice_data:
   Invoice.save_to_csv(invoice_data)
   return invoice_data
  return None
class DataParser:
 """
 数据分析类
 对识别返回后的数据进行整理,并于默认信息对比,查看有无错误
 这里只简单实现整理信息和检查名称和税号的方法,有兴趣可以增加其他丰富的方法
 """
 def __init__(self, invoice_data):
  self.invoice_data = invoice_data
 def get_detail_message(self):
  """
  对得到的发票信息的格式进行整理
  :return: 返回整理好的发票信息
  """
  values = [value for value in self.invoice_data.values()]
  detail_mess = f"完整信息为:" \
   f"\n发票代码: {values[1]}\n发票号码: {values[2]}\n开票日期: {values[3]}" \
   f"\n合计金额: {values[4]}\n价税合计: {values[5]}\n销售方名称: {values[6]}" \
   f"\n销售方税号: {values[7]}\n购方名称: {values[8]}\n购方税号:{values[9]}"
  return detail_mess
 def get_brief_message(self):
  """
  将信息中的名称和税号和默认值进行对比
  只做对错判断,读者丰富一下可以增加指出错误位置的信息
  :return: 返回判断的信息
  """
  if self.invoice_data["购方名称"] == config["company_name"]:
   brief_mess = "购方名称正确"
  else:
   brief_mess = "!购方名称错误!"
  if self.invoice_data["购方税号"] == config["company_tax_number"]:
   brief_mess += "\n购方税号正确"
  else:
   brief_mess += "\n!购方税号错误!"
  return brief_mess
 def parse(self):
  brief_mess = self.get_brief_message()
  detail_mess = self.get_detail_message()
  return brief_mess, detail_mess
class Pushover:
 """
 消息推送类
 本次使用Pushover为推送消息软件(30 RMB,永久,推荐)
 官网 https://pushover.net/
 可以向微信一样把相关信息推送至不同设备
 如果不需要可以把相关代码注释掉
 """
 @staticmethod
 def push_message(message):
  message += ">>>来自Python发票校验"
  try:
   requests.post("https://api.pushover.net/1/messages.json", data={
    "token": "你的Token",
    "user": "你的User",
    "message": message
   })
  except Exception as e:
   print(time.ctime()[:-5], "Pushover failed", e, sep="\n>>>>>>>>>>\n")

 2. 微信机器人文件 – Wechat
包含一个部分:微信处理类 Wechat
作用是初始化机器人,对微信的消息进行处理,分析并作出回应。

# -*- coding: utf-8 -*-
# Wechat.py
import os
from wxpy import *
class Wechat:
 """
 微信处理类
 对微信的消息进行处理,分析并作出回应
 """
 def __init__(self, group_name, admin_name):
  self.bot = Bot() # 类被实例化的时候即对机器人实例化
  self.group_name = group_name # 指定群聊名
  self.admin_name = admin_name # 管理员微信名
  self.received_mess_list = [] # 过滤后的消息列表
  self.order_list = [] # 管理命令列表
  self.pic_list = [] # 待解析图片绝对路径列表
 def get_group_mess(self):
  """
  方法--获取消息
  获取所有正常消息,进行过滤后存进消息列表
  """
  # 调用此方法时先清空上次调用时列表所存储的数据
  self.received_mess_list = []
  for message in self.bot.messages:
   # 如果为指定群聊或管理员的消息,存入group_mess
   sender = message.sender.name
   # >>>这里有一点要注意,如果你是用一个微信作为机器人且作为管理员<<<
   # >>>然后用这个微信号在群聊发消息,则信息sender会之指向自己而不是群聊<<<
   # >>>建议使用单独一个微信号作为机器人
   if sender == self.group_name or sender == self.admin_name:
    self.received_mess_list.append(message)
   # 其他的消息过滤掉
   self.bot.messages.remove(message)
  return None
 def parse_mess(self):
  """
  方法--处理群聊消息
  过滤获得的指定群聊消息
  设定所有新增群聊图片的绝对路径及群聊中产生的文字命令
  """
  # 调用此方法时先清空上次调用时列表所存储的数据
  self.pic_list = []
  self.order_list = []
  # self.group_order = []
  for message in self.received_mess_list:
   # 如果信息类型为图片,则保存图片并添加到图片列表
   if message.type == 'Picture' and message.file_name.split('.')[-1] != 'gif':
    self.pic_list.append(Wechat.save_file(message))
   # 如果消息类型为文字,则视为命令,保存到命令列表中
   if message.type == 'Text':
    self.order_list.append(message)
  return None
 @staticmethod
 def save_file(image):
  """
  方法--存储图片
  这里使用静态方法,是因为本方法和类没有内部交互,静态方法可以方便其他程序的调用
  解析名称,设定绝对路径,存储
  :param image: 接收到的图片(可以看成是wxpy产生的图片类,它具有方法和属性)
  :return: 返回图片的绝对路径
  """
  path = os.getcwd()
  # 如果路径下没有Pictures文件夹,则创建,以存放接收到的待识别图片
  if "Pictures" not in os.listdir():
   os.mkdir("Pictures")
  # 设定一个默认的图片格式后缀
  file_postfix = "png"
  try:
   # 尝试把图片的名称拆分,分别获取名称和后缀
   file_name, file_postfix = image.file_name.split('.')
  except Exception:
   # 当然有时候可能拆分不了,就把默认的后缀给它
   file_name = image.file_name
  # 赋予绝对路径
  file_path = path + '/Pictures/' + file_name + '.' + file_postfix
  # 将图片存储到指定路径下
  image.get_file(file_path)
  return file_path
 def send_group_mess(self, message):
  """
  方法--发送群消息
  :param message: 需要发送的内容
  """
  try:
   # 如果群聊名称被改变,搜索时会报错,如果找不到群聊,消息不会发送
   group = self.bot.groups().search(self.group_name)[0]
   group.send(message)
  except IndexError:
   print("找不到指定群聊,信息发送失败")
   return None
 def send_parse_log(self):
  """
  方法--发送查询日志
  向群聊内发送查询日志
  """
  try:
   # 如果群聊名称被改变,搜索时会报错,如果找不到群聊,消息不会发送
   group = self.bot.groups().search(self.group_name)[0]
  except IndexError:
   print("找不到指定群聊,查询日志发送失败")
   return None
  try:
   group.send_file("./work_log.csv")
  except:
   group.send("Oops, no log yet")
  return None
 def send_system_log(self):
  """
  方法--发送系统日志
  向群聊内发送查询日志
  """
  try:
   # 如果群聊名称被改变,搜索时会报错,如果找不到群聊,消息不会发送
   group = self.bot.groups().search(self.group_name)[0]
  except IndexError:
   print("找不到指定群聊,系统日志发送失败")
   return None
  try:
   group.send_file("./system_log.text")
  except:
   group.send("System log not found")
  return None

 3. 主文件 – Main
包含一个main函数,一部分为发票识别和处理,另一部分对于指令做出反应。

# -*- coding: utf-8 -*-
# Main.py
import time
from Utils import Invoice, DataParser
from Config import config
from Wechat import *
# Author : 达希
# Email : way2go.dash@gmail.com
def main():
 """
 主方法
 一部分为发票识别和处理,另一部分对于指令做出反应
 """
 # 输出重定向,将print语句都写进系统日志文件
 file = open("./system_log.text", "a+")
 sys.stdout = file
 # 实例化微信机器人,传入群聊名和管理员名
 wechat = Wechat(config["group_name"], config["admin_name"])
 while True:
  time.sleep(1)
  wechat.get_group_mess()
  wechat.parse_mess()
  # 若群聊有要处理的图片,则迭代解析
  if wechat.pic_list:
   for pic in wechat.pic_list:
    invoice_data = Invoice.run(pic)
    if invoice_data:
     data_parser = DataParser(invoice_data)
     brief_mess, detail_mess = data_parser.parse()
     wechat.send_group_mess(detail_mess) # 先发送发票识别详细信息
     time.sleep(0.5)
     wechat.send_group_mess(brief_mess) # 返回名称和税号是否有错误
    else:
     wechat.send_group_mess("请求未成功,请重试或联系管理员")
  # 若有相关命令,则做出相应反应
  if wechat.order_list:
   for order in wechat.order_list:
    if "开票信息" in order.text:
     wechat.send_group_mess(config["company_name"])
     time.sleep(0.5)
     wechat.send_group_mess(config["company_tax_number"])
    elif "SEND LOG" in order.text:
     wechat.send_parse_log()
    elif "SEND SYSTEM LOG" in order.text:
     wechat.send_system_log()
    elif "BREAK" in order.text:
     wechat.send_group_mess("收到关机指令,正在关机")
     file.close()
     return None
if __name__ == "__main__":
 main()

4. 配置文件 – Config

包含微信的配置文件信息

config = {
 "group_name": "发票校核ASAP", # 校核群聊名称,由于本代码默认没有同名群聊,所以建议设为复杂值
 "admin_name": "达希", # 管理员微信名(非备注)
 "company_name": "代码网络技术无限公司", # 默认购方名称
 "company_tax_number": "XXX00000000000XXX" # 默认购方税号
}

另外,代码在运行时会在同文件夹下创建一个Picture的文件夹,用于存储待解析的图片,会创建 work_log.csv 文件,用于存储识别信息的记录,还有 system_log.text 用于输出运行相应的日志。

由于本身需求较少,所以以上代码功能相对单薄,仅仅作为一个辅助的小脚本使用。若要进行优化完善,wxpy库提供了很多丰富的功能,可以在此基础上打造更加合理完善的,符合个性化需求的微信机器人。

总结

到此这篇关于Python制作发票自动校核微信机器人的文章就介绍到这了,更多相关Python制作发票自动校核微信机器人内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 如何用Python做一个微信机器人自动拉群

    引言 微信群的用户添加逻辑是 -- 当群人数达到100人后,用户无法再通过扫描群二维码加入,只能让用户先添加群内联系人微信,再由联系人把用户拉进来.这样,联系人员的私人微信会添加大量陌生人,给其带来不必要的打扰,而且纯人工操作,也容易出现纰漏. 那么,是否可以通过代码,做一个自动拉群机器人呢? 由微信机器人来实现自动加群功能,一劳永逸解决人工拉群的麻烦. 当然可以.西秦公子 就用Python 创造了一个微信自动拉群机器人,并把它部署运行在UCloud云平台上. 现在,他把机器人构建过程及代码 都

  • Python实现微信机器人的方法

    最近在学python的过程中无意间发现一个python库:wxpy,其可以实现让微信自动接收.处理消息并进行回复的一系列功能.感觉挺有意思的,便自行摸索学习,并成功地实现了其功能. 当我们打开微信,就会秒收到一些活跃分子的回复,有的时候感觉对方回答很在理,但是有的时候发现对方的回答其实是驴唇不对马嘴,仔细深究发现,原来对方是机器人. 首先需要安装wxpy库,其次需要去图灵机器人官网注册一下,获得一个机器人API即可实现微信机器人.http://www.turingapi.com/ 注册完成之后,

  • 手把手教你使用Python创建微信机器人

    微信,一个日活10亿的超级app,不仅在国内社交独领风骚,在国外社交也同样占有一席之地,今天我们要将便是如何用Python来生成一个微信机器人,突然想起鲁迅先生曾经说过的一句话: 因为是微信机器人系列的第一篇文章,所以猪哥会特别详细的讲解每一地方,尽量使每一位想学习的同学都能顺顺利利的开始,下面就让我们一起来做些有趣的事吧! 一.项目介绍 1.微信库选择 python关于开发微信的库主要有itchat和wxpy,而wxpy底层是调用的itchat,所以如果你只是要使用的话建议使用wxpy库,它比

  • python实现微信机器人: 登录微信、消息接收、自动回复功能

    安装wxpy pip install -U wxpy 登录微信 # 导入模块 from wxpy import * # 初始化机器人,扫码登陆 bot = Bot() 运行以上代码,会生成一个二维码,通过图片扫描二维码即可登录微信. 如果是在服务器上运行代码,无法显示图片的时候, 可以选择通过终端显示二维码图片, 只需要将代码改成: from wxpy import * bot = Bot(console_qr=True) 运行的效果如下: 当然,为了安全,这个二维码做了模糊处理 如果你认为每次

  • python使用itchat库实现微信机器人(好友聊天、群聊天)

    itchat是一个开源的微信个人号接口,可以使用该库进行微信网页版中的所有操作,比如:所有好友.添加好友.拉好友群聊.微信机器人等等.详细用户请看文档介绍,在这里. 本文主要使用该库完成一个能够处理微信消息的的图灵机器人,包括好友聊天.群聊天. 1.itchat库的安装 pip install itchat 安装完成后运行以下代码,会出现出现一张二维码,扫码登陆之后将会登陆微信网页. 2.登陆 import itchat # 登陆 itchat.auto_login() # 可设置hotRelo

  • Python实现企业微信机器人每天定时发消息实例

    1.背景 由于办公需要"每天定时推送某消息用来提醒群里面所有人",于是决定用企业微信自带的机器人来实现此功能.具体方法我来一一讲述. 2.企业微信API 具体见官网说明:https://work.weixin.qq.com/help?person_id=1&doc_id=13376 3.想法 想到几种方式: 直接写个sh脚本,并用linux定时器执行此脚本就可以了.这种方式简单实用,不过缺点就是修改起来稍微麻烦一点写个Qt/VS客户端程序,做好页面和每天想推送的内容,还是有点麻

  • Python实现发票自动校核微信机器人的方法

    制作初衷: 外地开了票到公司后发现信息有错误,无法报销: 公司的行政和财务经常在工作日被问及公司开票信息,影响心情和工作: 引入相应的专业APP来解决发票问题对于一般公司成本较高: 看到朋友孟要早睡写过脚本来解决这个问题,但因为公司场景不相同,无法复用,所以新写了一个 本代码使用简单的封装方法,并做了比较走心的注释,希望能给初学Python的小伙伴提供一些灵感,也能让有实际需求的人可以快速修改.使用. 源码地址:https://github.com/yc2code/WechatInvoicePa

  • 基于Python实现定时自动给微信好友发送天气预报

    效果图 from wxpyimport * import requests from datetimeimport datetime import time from apscheduler.schedulers.blockingimport BlockingScheduler#定时框架 bot = Bot(cache_path=True) tuling = Tuling(api_key=你的api')#机器人api def send_weather(location): #准备url地址 pa

  • Python+Appium实现自动抢微信红包

    环境准备 appium环境 安卓手机 usb数据线 python环境 实现思路 我们收到红包和消息都是自动置顶到第一个,于是我们打开第一个判断是否有红包,没有则隐藏此窗口.如果有则判断红包是否可以领取,如果有则领取红包,否则删除此红包(不然会影响后面的判断) 然后再进行循环运行和判断. code 首先看一下配置信息,因为我使用得是真机小米9安卓10的系统,代码实现如下具体的信息填写请根据自己的真实情况修改: desired_caps = { "platformName": "

  • 采用python实现简单QQ单用户机器人的方法

    采用python实现简单QQ单用户机器人的方法如下: 一.首先我们查看一下关于3GQQ的相关协议:     对此,打开一个支持WAP的浏览器,可以使用Firefox的wmlbrowser插件,打开FF后,访问地址 https://addons.mozilla.org/zh-CN/firefox/search/?q=wmlbrowser&cat=all&x=17&y=11    二.进入3GQQ的进行协议分析     3GQQ的地址是:http://pt.3g.qq.com/s?ai

  • python函数超时自动退出的实操方法

    本章给大家在项目使用时候,常见的一种情况解决案例,即是当我们调用多个线程,使用了同一个函数去处理数据的时候,有些用函数已经处理完成,但是有些还没有,这就需要我们将任务进行分割,然后当一小部分任务执行后,退出来,另外没有执行的完成超时的就继续去执行,下面就针对遇到这些问题的小伙伴,给大家提供解决参考. 安装timeout-decorator库: pip3 install timeout-decorator 编写异常语句: @timeout_decorator.timeout(5, timeout_

  • 用Q-learning算法实现自动走迷宫机器人的方法示例

    项目描述: 在该项目中,你将使用强化学习算法,实现一个自动走迷宫机器人. 如上图所示,智能机器人显示在右上角.在我们的迷宫中,有陷阱(红色×××)及终点(蓝色的目标点)两种情景.机器人要尽量避开陷阱.尽快到达目的地. 小车可执行的动作包括:向上走 u.向右走 r.向下走 d.向左走l. 执行不同的动作后,根据不同的情况会获得不同的奖励,具体而言,有以下几种情况. 撞到墙壁:-10 走到终点:50 走到陷阱:-30 其余情况:-0.1 我们需要通过修改 robot.py 中的代码,来实现一个 Q

  • python实现dnspod自动更新dns解析的方法

    复制代码 代码如下: def ddns():"""用当前ip更新ddns"""headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/json"}conn = httplib.HTTPSConnection("dnsapi.cn", timeou

  • python调用API实现智能回复机器人

    本文实例为大家分享了python调用API实现机器人的具体代码,供大家参考,具体内容如下 注意事项: 下面代码中的APIKEY需要替换 需要有自己的公众号平台,并且自己成为管理员, http://www.tuling123.com 这个网址上要有账号并且创建机器人,在帮助中心里可以获取APIkey,然后填入下方的代码中. #图灵机器人 def talks_robot(info = '你叫什么名字'): api_url = 'http://www.tuling123.com/openapi/api

随机推荐