电子发票太多,想统计下总额异常困难,网上工具不好用,花了2个小时实现一份,测试过中石油、京东开具的电子发票还行,部分发票名称失败有问题不影响统计,有需要的小伙伴自己拿去改吧。

import cmd

import sys

import json

import pdfplumber

import os

from pprint import pprint

class FapiaoShell(cmd.Cmd):

""" 发票 """

intro = '欢迎使用发票提取工具,输入?(help)获取帮助消息和命令列表,CTRL+C退出程序。\n'

prompt = '\n输入命令: '

doc_header = "详细文档 (输入 help <命令>):"

misc_header = "友情提示:"

undoc_header = "没有帮助文档:"

nohelp = "*** 没有命令(%s)的帮助信息 "

def __init__(self):

super().__init__()

def do_load(self, arg):

""" 加载发票 例如:load D:\ """

if not os.path.isdir(arg):

print('参数必须是目录!')

return

os.chdir(os.path.dirname(arg))

pdfs = []

for root, _, files in os.walk(arg):

for fn in files:

ext = os.path.splitext(fn)[1].lower()

if ext != '.pdf':

continue

fpth = os.path.join(root, fn)

fpth = os.path.relpath(fpth)

print(f'发现pdf文件: {fpth}')

pdfs.append(fpth)

pdf_ctxs = self._parse_pdfs(pdfs)

total = {

'内容': pdf_ctxs,

'发票数': len(pdf_ctxs),

'总计': 0,

}

for fpth, info in pdf_ctxs:

total['总计'] += float(info['总计'])

print('\n保存到 结果.json...')

with open("结果.json", 'w', encoding='utf-8') as json_file:

json.dump(total,

json_file,

ensure_ascii=False,

sort_keys=True,

indent=4,

separators=(', ', ': '))

print('完成!')

def _parse_pdfs(self, pdfs):

""" 分析 """

result = []

for fpth in pdfs:

info = {}

with pdfplumber.open(fpth) as pdf:

page = pdf.pages[0]

if '增值税电子普通发票' not in ''.join(page.extract_text()):

result.append((fpth, {}))

inf = self._extrace_from_words(page.extract_words())

info.update(inf)

inf = self._extrace_from_table(page.extract_tables()[0])

info.update(inf)

result.append((fpth, info))

return result

def _extrace_from_words(self, words):

""" 从单词中提取 """

info = {}

lines = {}

for word in words:

top = int(word['top'])

bottom = int(word['bottom'])

pos = (top + bottom) // 2

text = word['text']

if pos not in lines:

lines[pos] = [text]

else:

lines[pos].append(text)

lines_pack = []

last_pos = None

for pos in sorted(lines):

arr = lines[pos]

if len(lines_pack) > 0 and pos - last_pos <= 10:

lines_pack[-1] += arr

continue

lines_pack.append(arr)

last_pos = pos

continue

for pack in lines_pack:

for idx, line in enumerate(pack):

if '电子普通发票' in line:

info['标题'] = line

continue

if '发票代码:' in line:

info['发票代码'] = line.split(':')[1]

continue

if '发票号码:' in line:

info['发票号码'] = line.split(':')[1]

continue

if '开票日期:' in line:

year = line.split(':')[1]

month = [ln for ln in pack if ln.isdigit()][0]

day = [ln[:2] for ln in pack if '日' in ln][0]

info['开票日期'] = f'{year}-{month}-{day}'

continue

if '机器编号:' in line:

info['机器编号'] = [ln for ln in pack if ln.isdigit()

and len(ln) > 10][0]

continue

if '码:' in line:

c1 = pack[idx].split(':')[1]

c2 = pack[idx+1]

c3 = pack[idx+2]

c4 = pack[idx+3]

info['校验码'] = f'{c1} {c2} {c3} {c4}'

continue

if '收款人:' in line:

info['收款人'] = line.split(':')[1]

continue

if '开票人:' in line:

info['开票人'] = line.split(':')[1]

continue

return info

def _extrace_from_table(self, table):

""" 从表中提取 """

info = {}

if len(table) != 4:

return None

# 购买方

for cell in table[0]:

if not cell:

continue

lines = cell.splitlines()

for line in lines:

if '名 称:' in line:

info['购买方名称'] = line.split(':')[1]

continue

if len(line) == 18 and line.isalnum():

info['购买方税号'] = line

continue

if len(line) == 27:

if '密码' not in info:

info['密码'] = []

info['密码'].append(line)

continue

# 详细

for cell in table[1]:

if not cell:

continue

lines = cell.splitlines()

for line in lines:

if '货物或应税劳务、服务名称' in line:

info['商品'] = lines[1:-1]

break

if '金 额' in line:

info['总金额'] = lines[-1][1:]

break

if '税 额' in line:

info['总税额'] = lines[-1][1:]

break

# 合计

for cell in table[2]:

if not cell:

continue

lines = cell.splitlines()

for line in lines:

if '¥' in line:

info['总计'] = line[1:]

# 销售方

for cell in table[3]:

if not cell:

continue

lines = cell.splitlines()

for line in lines:

if '名 称:' in line:

info['销售方名称'] = line.split(':')[1]

continue

if len(line) == 18 and line.isalnum():

info['销售方税号'] = line

continue

return info

if __name__ == '__main__':

try:

FapiaoShell().cmdloop()

except KeyboardInterrupt:

print('\n\n再见!')

python提取发票信息发票识别_分享一个电子发票信息提取工具(Python)相关推荐

  1. 分享一个电子发票信息提取工具(Python)

    电子发票太多,想统计下总额异常困难,网上工具不好用,花了2个小时实现一份,测试过中石油.京东开具的电子发票还行,部分发票名称失败有问题不影响统计,有需要的小伙伴自己拿去改吧. import cmd i ...

  2. python制作浏览器插件_分享一个火车浏览器脚本插件python中文分词

    最近在采集一批信息,发现火车浏览器的自带分词插件,分词效果不是很理想,在网上找了一个API分词接口:pullword 其实对于火车浏览器脚本插件用PHP和python都可以写,之前做了一个PHP分词插 ...

  3. 用python制作英文字典的分析_分享一个自己做的英文科学写作检查器

    最近在读一本神书,牛津大学出版的<Scientific Writing and Communication>,边阅读边检查书里面说的那些英文科学论文写作中经常出现的很俗的桥段,很多余的短语 ...

  4. 一个电子发票开票平台的系统架构设计(02)

    这次主要从网络拓扑结构上讲一下平台是怎么运作的.先看图片 一般来说大家都会选择一家云服务商作为主要使用环境,另外一家作为备用环境的,但由于客户的特殊性所以先不要纠结这里的不同服务商. 简单说明一下: ...

  5. 一个电子发票开票平台的系统架构设计(01)

    公司需要帮助客户开发一个电子发票平台,使用者为普通消费者,商户,管理人员三种角色,分别又有对应的使用场景.又想要实现前后端分离,所以把公司常用的架构做了调整,来满足客户的需求.先放上架构图看一下: 因 ...

  6. 分享一个IIS日志分析工具-LogParse

    分享一个IIS日志分析工具 LogParser工具的使用 1)先安装LogParser 2.2.msi ,是一个命令行工具,功能强大,但使用不便: 下载地址:http://www.microsoft. ...

  7. 给大家分享一个打卡的工具,是一个微信小程序,名字叫小打卡

    给大家分享一个打卡的工具,是一个微信小程序,名字叫小打卡.之前Ben和我讨论过,有没有这样一个方便的工具,能把每天工作学到的零碎知识点记录下来,或者是工作中突然来了一些稍纵即逝的灵感,如果不及时记下来 ...

  8. 工具 | 分享一个截长图工具

    1024G 嵌入式资源大放送!包括但不限于C/C++.单片机.Linux等.关注微信公众号[嵌入式大杂烩],回复1024,即可免费获取! 分享一个实用的小工具:FastStone Capture.这个 ...

  9. JAVA识别PDF和OFD电子发票并解析为java对象

    上一篇我们说了java实现电子发票中的发票税号等信息识别的几种可用方案,最后博主选取了识别文件二维码的方式,而且文章最后也说了,这种有局限性,去到的信息有限,而且针对OFD格式也得继续想办法,那接下来 ...

最新文章

  1. USEARCH11新功能——OTU表抽平otutab_rare
  2. 帕斯卡三角形杨辉三角
  3. VCSA6.7 备份和还原
  4. JSP 语法2 都在百分号里面: 5.@符号加JSP三种指令标签 6
  5. 奥鹏秋季计算机基础,14秋季奥鹏东北师范大学计算机应用基础离线作业
  6. 解决vue+php跨域问题
  7. 用VBA破解Excel密码
  8. js获取数组第一个和最后一个元素
  9. 2018 蓝桥杯省赛 B 组模拟赛(一)青出于蓝胜于蓝(DFS序+树状数组)
  10. 磁盘 I/O 和网络
  11. SHIMANO套件差别详解
  12. eureka心跳_8个Eureka优化技巧,让效率提高10倍
  13. oa系统用什么云服务器,oa系统用什么云服务器
  14. log4j2输出中文乱码
  15. Java炸弹人实现及源码
  16. 支付宝香港落地记:那些你不知道的争论和故事
  17. python入门学习随记(十)
  18. 传感器和算法如何让机器人实现避障?
  19. bpmnjs activiti 添加定时事件timeDate,timeDuration,timeCycle
  20. 《未来简史》中文有声书MP3下载

热门文章

  1. 轻快PDF阅读器下载中文版
  2. 多校HDU.5724 Chess
  3. 计算机学院校运会解说词,大学学院运动会入场解说词
  4. 【Threejs效果:挖空几何体】ThreeBSP实现墙体挖洞
  5. 致所有仍然关注BreezeMaphack的朋友
  6. 小区宽带网络解决方案
  7. 【杂谈与乱码】我们过度解读了鲁迅先生了么?
  8. Css Reset -Css样式重置
  9. Play-To-Earn游戏将接管电子游戏行业?
  10. [CISCN]2020