一、问题缘起

平时工作中会接触到很多发票,报销前需要把发票的各种信息包括:发票号码、发票代码、校验码、金额等信息录入到报账系统中。如果手机一个个复制粘贴,非常麻烦,而且容易出错,如果采用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')

最后的效果展示:

2024.11.2更新发票信息提取工具

#Gordon 编写;运行前安装Python, 在cmd下面pip install pdfplumber,xlwt
import pdfplumber
import re
import os
import xlwt

# 创建工作簿
wb = xlwt.Workbook()
# 创建表单
sh = wb.add_sheet('sheet 1')
for i, name in zip(range(7), ['发票代码', '发票号码', '开票日期', "校验码", '公司', '金额', '税额']):
    sh.write(0, i, name)

def re_text(bt, text):
    m1 = re.search(bt, text)
    if m1:
        return re_block(m1.group(1))
    return ""

def re_block(text):
    return re.sub(r"[ )):]", "", text)

def read():
    filenames = [file.name for file in os.scandir(".") if file.name.endswith(".pdf")]
    row = 1

    for filename in filenames:
        print(filename)
        try:
            with pdfplumber.open(filename) as pdf:
                first_page = pdf.pages[0]
                pdf_text = first_page.extract_text()

                if '发票' not in pdf_text:
                    continue

                # 获取发票信息
                fapiaodaima = re_text(r'发票代码.*?(\d+)', pdf_text)
                fapiaohaoma = re_text(r'发票号码.*?(\d+)', pdf_text)
                kaipiaoriqi = re_text(r'开票日期(.*)', pdf_text)
                jiaoyan = re_text(r'校 验 码\s*[::]\s*([a-zA-Z0-9 ]+)', pdf_text)
                

                heji_match = re_text(r'合.*计(.*)', pdf_text)
#                 heji = re.split(r"¥|¥", heji_match) if heji_match else ["", ""]
                heji = re.split(r"¥|¥", heji_match) if heji_match else ["", ""] #re.split(r" ", heji_match) #

                jine = heji[1] if len(heji) > 1 else "".join(heji)
                shuie = heji[2] if len(heji) > 2 else "".join(heji)
                
                # 提取公司名称
                company_match = re.findall(r'名.*?称\s*[::]\s*([一-龟]+)', pdf_text)
                gongsi = re_block(company_match[-1]) if company_match else ""

                lst=[fapiaodaima,fapiaohaoma,kaipiaoriqi,jiaoyan,gongsi,jine,shuie]
                
                print(lst)
                
                # 写入Excel
                for i, value in enumerate(lst):
                    sh.write(row, i, value)
                row += 1

        except Exception as exc:
            print(f"Error processing {filename}: {exc}")

    # 保存Excel
    wb.save('发票信息.xls')
read()

三、批量录入

现在发票的数据信息提取出来了,下一步是把这些信息批量录入到网上的报账系统中。下面是之前做好一个源码,如果简单修改一下就可以实现读取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")

四、学后反思

  1. 本次项目把数据收集、文件写入,再到文件读取、网上批量录入集中用Python编程来实现,部分实现了办公的自动化,减轻了人力的负担,提升了工作的效率。
  2. 在程序运行过程中也发现,有些pdf表中的信息无法识别的情况,这时就可能要人工进行干预,补充信息,把信息规整完毕后就可以用批量填充工具进行填充了。
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐