#
我老婆是一名会计。我发现会计比做程序员要麻烦多了,要记住各种财务政策,跟进时代的税率,掌握处理财务事情的逻辑等等等.....虽然她身处于一家小公司,但是我仍然可以感觉到她面对海量数据处理上的无力感。于是我自学了一下python语言,让自己具备一点写小插件的能力,能给予她更多的帮助。学习久了,感觉python挺好玩的,或许在家无聊时分,可以python弄一些AI方面的东西。
# 批量处理电子发票的工具
电子发票大多是pdf格式的,我们假设只读取pdf的,那么python有一个 PyMuPDF 的库正好能够读取pdf格式的内容。那么就好办了。
import fitz
block_list = fitz.open(pdf_url).load_page(0).get_text("blocks")
1
2
3
2
3
可以获取到pdf内类似html的 div块的坐标、大小、和文字信息。
大概流程如下图:
这其中最主要的费力点就是要知道一张发票上的关键信息,然后去找到对应关键点的坐标,不过不用担心,我把我找到的数据代码贴出来,自行修改吧。准确率蛮高的,得到我老婆的大力夸奖,哈哈哈
import fitz
import os
from tkinter import filedialog
import math
import xlwt
if __name__ == "__main__":
filePath = filedialog.askdirectory()
print('选择的目录地址为:', filePath)
file_list = []
for roots, dirs, files in os.walk(filePath):
file_list = files
break
file_list = list(filter(lambda x:x[-4:]=='.pdf' ,file_list))
print('pdf文件为:',file_list)
if len(file_list):
wb = xlwt.Workbook()
wbsht = wb.add_sheet('发票统计')
header = ['发票名称','名称',"纳税人识别号","货物或应税劳务、服务名称","规格型号","单位","数量","单价","金额","税率","税额","发票代码","发票号码","开票时间","校验码","销售方名称","销售方纳税人识别号码","销售方地址、号码","销售方开户行及账号"]
for i in range(len(header)):
wbsht.write(0,i,header[i])
tax_list=[]
for ii in range(len(file_list)):
pdf = file_list[ii]
wbsht.write(ii+1,0,pdf)
pdf_url = os.path.join(filePath,pdf)
doc = fitz.open(pdf_url)
content = {}
page1 = doc.load_page(0)
page1_text = page1.get_text("blocks")
message_list = list(page1_text)
for item in message_list:
value = '-'.join(filter(lambda x:x ,item[4].split('\n')))
print(item[0],item[1],value)
if item[0]==27:
item_list = value.split('-')
wbsht.write(ii+1,header.index('货物或应税劳务、服务名称'),item_list[0])
wbsht.write(ii+1,header.index('规格型号'),item_list[1])
wbsht.write(ii+1,header.index('单位'),item_list[2])
wbsht.write(ii+1,header.index('数量'),item_list[3])
wbsht.write(ii+1,header.index('单价'),item_list[4])
wbsht.write(ii+1,header.index('金额'),item_list[5])
wbsht.write(ii+1,header.index('税率'),item_list[6])
wbsht.write(ii+1,header.index('税额'),item_list[7])
if item[0]==108:
item_list = value.split('-')
wbsht.write(ii+1,header.index('名称'),item_list[0])
wbsht.write(ii+1,header.index('纳税人识别号'),item_list[1])
if item[0]== 475.0:
if math.floor(item[1])==10:
wbsht.write(ii+1,header.index('发票代码'),value)
if math.floor(item[1])==28:
wbsht.write(ii+1,header.index('发票号码'),value)
if math.floor(item[1])==63:
wbsht.write(ii+1,header.index('校验码'),value)
if item[0]== 477:
wbsht.write(ii+1,header.index('开票时间'),'-'.join( value.split(' ')))
if item[0]== 106:
if math.floor(item[1])==293:
item_list = value.split('-')
wbsht.write(ii+1,header.index('销售方名称'),item_list[0])
wbsht.write(ii+1,header.index('销售方纳税人识别号码'),item_list[1])
# wbsht.write(ii+1,header.index('销售方地址、号码'),item_list[2])
if math.floor(item[1])==324:
wbsht.write(ii+1,header.index('销售方地址、号码'),value)
if math.floor(item[1])==336:
wbsht.write(ii+1,header.index('销售方开户行及账号'),value)
wb.save('./发票相关.xlsx')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
代码还是蛮简单的,不过对于我这种新手来说纯纯够了
# 批量处理图片付款信息
这里其实是利用了 Image 模块读取信息截图的数据,然后用numpy转换成向量,接着使用easyocr读取该矢量获取图片上的文字信息,最后根据坐标位置确定具体数值。关键代码大概如下:
img = Image.open(png_url)
numpy_array = asarray(img)
reader = easyocr.Reader(['ch_sim','en'])
result = reader.readtext(numpy_array)
1
2
3
4
2
3
4
但是这里仅仅可以用于某一个规格的收款图片,bug太多,就不贴图了,而且没有显卡,所以也不能做一些训练和加速,这个临时项目就搁置了,等攒钱了买一块显卡再进行深一度的优化吧。
# 批量处理excel数据
未完待续....