一、问题缘起
平时工作中会接触到很多发票,报销前需要把发票的各种信息包括:发票号码、发票代码、校验码、金额等信息录入到报账系统中。如果手机一个个复制粘贴,非常麻烦,而且容易出错,如果采用Python的话则很容易把信息提取到Excel表中,这样再分别录入到网上就快捷多了。为了达到这个目的,我在网上找了一个代码,测试了一下还不错。
二、初步解决
我借鉴网上的代码,同时把源代码进行了修改,增加了批量写入Excel文件中的功能,不仅识别率高,而且运行速度快。源码用os.walk()来遍历pdf,pdfplumber来识别pdf文件,最后用xlwt来写入到xls文件中。
import pdfplumber
import re
import os
import xlwt
# 创建工作簿
wb = xlwt.Workbook()
# 创建表单
sh = wb.add_sheet('sheet 1')
sh.write(0, 0, '发票代码')
sh.write(0, 1, '发票号码')
sh.write(0, 2, '开票日期')
sh.write(0, 3, '校验码')
sh.write(0, 4, '金额')
sh.write(0, 5, '公司')
def re_text(bt, text):
m1 = re.search(bt, text)
if m1 is not None:
return re_block(m1[0])
def re_block(text):
return text.replace(' ', '').replace(' ', '').replace(')', '').replace(')', '').replace(':', ':')
def get_pdf(dir_path):
pdf_file = []
for root, sub_dirs, file_names in os.walk(dir_path):
for name in file_names:
if name.endswith('.pdf'):
filepath = os.path.join(root, name)
pdf_file.append(filepath)
return pdf_file
def read():
filenames = get_pdf('.') # 修改为自己的文件目录
row = 1
for filename in filenames:
print(filename)
with pdfplumber.open(filename) as pdf:
first_page = pdf.pages[0]
pdf_text = first_page.extract_text()
if '发票' not in pdf_text:
continue
#print(pdf_text)
print('--------------------------------------------------------')
# print(re_text(re.compile(r'[\u4e00-\u9fa5]+电子普通发票.*?'), pdf_text))
# t2 = re_text(re.compile(r'[\u4e00-\u9fa5]+专用发票.*?'), pdf_text)
# if t2:
# print(t2)
print(re_text(re.compile(r'发票代码(.*\d+)'), pdf_text))
print(re_text(re.compile(r'发票号码(.*\d+)'), pdf_text))
print(re_text(re.compile(r'开票日期(.*)'), pdf_text))
print(re_text(re.compile(r'名\s*称\s*[::]\s*([\u4e00-\u9fa5]+)'), pdf_text))
print(re_text(re.compile(r'纳税人识别号\s*[::]\s*([a-zA-Z0-9]+)'), pdf_text))
print(re_text(re.compile(r'税*额.*(.*[0-9.]+)'), pdf_text))
fapiaodaima = re_text(re.compile(r'发票代码(.*\d+)'), pdf_text)
fapiaohaoma = re_text(re.compile(r'发票号码(.*\d+)'), pdf_text)
kaipiaoriqi = re_text(re.compile(r'开票日期(.*)'), pdf_text)
jiaoyan = re_text(re.compile(r'校 验 码\s*[::]\s*([a-zA-Z0-9 ]+)'), pdf_text)[-6:]
xiaoxie = re_text(re.compile(r'小写.*(.*[0-9.]+)'), pdf_text)
print(f'校验码:{jiaoyan}',xiaoxie,sep="\n")
company = re.findall(re.compile(r'名.*称\s*[::]\s*([\u4e00-\u9fa5]+)'), pdf_text)
if company:
print(re_block(company[len(company)-1]))
gongsi = re_block(company[len(company)-1])
#lst = [fapiaodaima[-12:],fapiaohaoma[-8:],kaipiaoriqi[5:],jiaoyan,xiaoxie[3:],gongsi]
lst = [fapiaodaima[5:],fapiaohaoma[5:],kaipiaoriqi[5:],jiaoyan,xiaoxie,gongsi]
for i in range(6):
sh.write(row,i,lst[i])
row+=1
print('--------------------------------------------------------')
read()
# 保存
wb.save('发票信息.xls')
最后的效果展示:
三、批量录入
现在发票的数据信息提取出来了,下一步是把这些信息批量录入到网上的报账系统中。下面是之前做好一个源码,如果简单修改一下就可以实现读取Excel中的发票信息,然后批量录入到网上,而且还不会出错。
import time
import openpyxl # 用于读取excel表中的分数
import pyautogui # 用于控制键盘
from tkinter import *
def main():
"""调用tkinter,生成UI界面"""
root = Tk()
# 设置窗口前端显示
root.wm_attributes('-topmost', 1)
content = StringVar()
e = Entry(root, textvariable=content, width=30, bd=5, font=("Times New Roman", 13))
e.insert(0, "开始后请把光标放到要填充的位置!")
e.pack()
# 设置居中显示
screenwidth = root.winfo_screenwidth()
screenheight = root.winfo_screenheight()
width = 320
height = 170
size = "%dx%d+%d+%d" % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
root.geometry(size)
# 设置窗口标题及大小
root.title('成绩录入')
root['width'] = 310;
root['height'] = 165
# 设置按纽
def b_showup():
e.delete(0,END)
e.insert(0,'开始填充,请勿移动鼠标键盘!')
lst = read_lst()
time.sleep(1)
fit(lst)
def b_quitprog():
root.destroy()
b_show = Button(root, text='一键填充', width=10, height=1, font=("微软雅黑", 11), command=b_showup)
b_quit = Button(root, text="退出程序", width=10, height=1, font=("微软雅黑", 11), command=b_quitprog)
b_show.pack()
b_quit.pack()
root.mainloop()
def read_lst():
'''读取Excel表格,返回列表lst'''
lst = []
workbook = openpyxl.load_workbook("发票信息.xlsx")
sheet = workbook.active
for row in sheet.rows:
lst.append((str(row[0].value), str(row[1].value), str(row[2].value), str(row[3].value), str(row[4].value), str(row[5].value))) # 把每一行的两个数据存为一个元组,存入列表
return lst
def fit(lst):
'''把列表lst中的数据批量写在屏幕的指定位置'''
lst = read_lst()
for k in lst:
pyautogui.typewrite(k[0], 0.01)
pyautogui.press("tab")
pyautogui.typewrite(k[1], 0.01)
pyautogui.press("tab")
四、学后反思
- 本次项目把数据收集、文件写入,再到文件读取、网上批量录入集中用Python编程来实现,部分实现了办公的自动化,减轻了人力的负担,提升了工作的效率。
- 在程序运行过程中也发现,有些pdf表中的信息无法识别的情况,这时就可能要人工进行干预,补充信息,把信息规整完毕后就可以用批量填充工具进行填充了。