自动化工具-整理电子发票(Python实现PDF文件的读取和修改)_农民工老王的博客-程序员秘密

技术标签: python  reportlab  正则表达式  PyPDF2  Python  

博客主页:https://tomcat.blog.csdn.net
博主昵称:农民工老王
主要领域:Java、Linux、K8S
期待大家的关注点赞收藏留言
家乡

背景

我们部门偶尔加班,领导让我统计同事们的加班情况,并处理加班餐的报销工作,其中比较麻烦的一个事情是整理发票,我们公司对电子发票的要求是:

  1. 电子发票的文件名修改为日期+发票代码+发票号码。
  2. 电子发票需要打印出来,并在背面写上报销金额,消费时间,加班参与人员等报销信息。

每月有20多张报销发票,平均每天加班有10多名同事,光誊写这些名字就挺耗时。如果手动操作文件的重命名,也很容易出错。我就想到用代码来解决这个问题。Java在处理Excel表格,PDF文件稍显麻烦,我就用Python作为编程语言,写了个自动化工具,要求1是文件的重命名,实现起来就比较简单,可以复制原有的发票文件,存储为所要求的文件名即可;要求2的实现是通过在电子发票PDF文件中再加一页,并在其中写入报销信息,然后就可以直接批量双面打印。

实现

项目结构

我在PyCharm中创建了项目。其中outputForPrint为双面打印的输出文件夹,outputForRename为重命名后的输出文件夹,receiptOriginal为原始发票文件夹,msyh.ttc为字体文件,receipt.xlsx为存储报销信息的表格,receiptTool.py为python脚本。

在这里插入图片描述

表格内容

receipt.xlsx仅有sheet1工作表,内容如下表所示,备注中的金额与人员用英文分号进行分割。

日期 备注
4月01日 金额-50;人员-老王,老罗
4月06日 金额-300;人员-老王,肖美女,兵哥,阿杜,老李,老胡,小毛,老荣,老罗,涛哥,杰哥,核姐
4月07日 金额-275;人员-肖美女,兵哥,阿杜,老李,老胡,小毛,老荣,老罗,涛哥,杰哥,核姐
4月08日 金额-150;人员-老王,老荣,老罗,涛哥,杰哥,核姐
4月09日 金额-250;人员-老王,肖美女,兵哥,阿杜,老李,老胡,小毛,老荣,涛哥,核姐
4月11日 金额-250;人员-老王,肖美女,兵哥,老李,老荣,老罗,涛哥,杰哥,核姐,老姚
4月12日 金额-250;人员-老王,肖美女,兵哥,阿杜,老荣,老罗,涛哥,杰哥,核姐,老姚
4月13日 金额-250;人员-老王,肖美女,兵哥,阿杜,老荣,老罗,涛哥,杰哥,核姐,老姚
4月14日 金额-250;人员-老王,肖美女,兵哥,阿杜,老荣,老罗,涛哥,杰哥,核姐,老姚
4月16日 金额-175;人员-老王,阿杜,老荣,老罗,杰哥,核姐,老姚
4月18日 金额-225;人员-肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐
4月19日 金额-275;人员-老王,肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐,老姚
4月20日 金额-275;人员-老王,肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐,老姚
4月21日 金额-275;人员-老王,肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐,老姚
4月24日 金额-225;人员-老王,肖美女,阿杜,老荣,老罗,涛哥,杰哥,核姐,老姚
4月25日 金额-300;人员-老王,肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐,老姚,追风少年
4月26日 金额-275;人员-肖美女,兵哥,阿杜,老李,老荣,老罗,涛哥,杰哥,核姐,老姚,追风少年
4月27日 金额-275;人员-老王,肖美女,兵哥,老李,老荣,老罗,涛哥,杰哥,核姐,老姚,追风少年
4月28日 金额-275;人员-老王,肖美女,兵哥,阿杜,老李,老荣,涛哥,杰哥,核姐,老姚,追风少年

python代码

# ------------------------------------------
# Filename    : receiptTool.py
# Version     : 1.1
# Date        : 2022-7-15 19:50:15
# Author      : 农民工老王@CSDN
# Email       : [email protected]
# Website     : https://blog.csdn.net/monarch91
# Description : 用于处理电子发票
# ------------------------------------------

import pandas
import PyPDF2
import os
import pathlib
import pdfplumber
import re
from shutil import copyfile
from PyPDF2 import PdfFileReader
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen.canvas import Canvas
from reportlab.pdfbase import pdfmetrics, ttfonts

outputDir = "outputForRename"
printDir = "outputForPrint"
if not pathlib.Path(outputDir).is_dir():
    os.makedirs(outputDir)

if not pathlib.Path(printDir).is_dir():
    os.makedirs(printDir)

pdfmetrics.registerFont(ttfonts.TTFont('msyh', 'msyh.ttc'))
receiptData = pandas.read_excel("receipt.xlsx", sheet_name="Sheet1", index_col="日期")

for index, row in receiptData.iterrows():
    pdfPath = "receiptOriginal" + os.sep + str(index) + ".pdf"
    if type(index) == str and pathlib.Path(pdfPath).is_file():
        print("检测到%s有对应发票,正在处理。" % (index))

        pdfStr = ""
        with pdfplumber.open(pdfPath) as p:
            page = p.pages[0]
            pdfStr = page.extract_text()
        fpdm = re.search(r"发票代码[::]\s?(\d+)", pdfStr).group(1)
        fphm = re.search(r"发票号码[::]\s?(\d+)", pdfStr).group(1)

        receiptPdf = PdfFileReader(open(pdfPath, 'rb'))
        pdfSize = receiptPdf.getPage(0).mediaBox
        pdfH = float(pdfSize[2])
        pdfV = float(pdfSize[3])
        canvas = Canvas("temp.pdf", pagesize=(pdfH, pdfV))
        fontSize = 18 * pdfV / A4[1]
        canvas.setFont("msyh", fontSize)
        canvas.drawString(pdfH / 20, pdfV / 2 + fontSize * 1.5, index)
        for i, item in enumerate(row["备注"].split(";")):
            canvas.drawString(pdfH / 20, pdfV / 2 - fontSize * i * 1.5, item)
        canvas.save()

        pdf_merger = PyPDF2.PdfFileMerger()
        pdf_merger.append(pdfPath)
        pdf_merger.append("temp.pdf")

        pdfOutput = open(printDir + os.sep + index + "-print.pdf", 'wb')
        copyfile(pdfPath, outputDir + os.sep + index + "-" + fpdm + "-" + fphm + ".pdf")
        pdf_merger.write(pdfOutput)
        pdf_merger.close()

os.remove("temp.pdf")

运行效果

运行后,在控制台有以下输出:

在这里插入图片描述

顺利实现文件重命名:
在这里插入图片描述顺利生成用于双面打印的文件:
在这里插入图片描述用于双面打印的文件:
请添加图片描述


如需转载,请注明本文的出处:农民工老王的程序员秘密https://blog.csdn.net/monarch91 。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/monarch91/article/details/125806701

智能推荐

smarty与js冲突的非主流解决办法_smarty 与 jquery 冲突_erlanp的博客-程序员秘密

Smarty的使用中,有一些麻烦的事。比如在模版可以用{$data}这样的写法,但因为很多模版一般都有它独自的javascript,所以写成了 或 [{$data} 的样子。使用标签{literal}[javascript code]{/literal}虽然是一个解决办法,当然,你也可以为所需的javascript单独写个文件引用(麻烦)。但如果javascript中需要php变量时,这就不合适

经典面试题:移动零_加班狗的微博的博客-程序员秘密

题目给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。示例:输入: [0,1,0,3,12]输出: [1,3,12,0,0]思路通过设定快指针i 和慢指针j,将不为0的数字移动到数组的前方j对应的数字如果不为0(nums[j]),则将慢指针对应的数字(nums[i])改为nums[j],然后慢指针j+1然后把之后的将慢指针之后的改为0实现public void moveZeroes(int[] nums) {

VScode修改默认HTML代码_许大思的博客-程序员秘密

在VScode新建的HTML文档中输入!+tab键可生成HTML默认格式代码,未更改前的代码如下: Document123456789101112由于一些代码不需要使用,而每次生成后都需要删除,在这里我们修改默认的HTML代码找到VScode安装目录下的目标文件 VScode\resources\app\extensi...

2021-10-23 617. 合并二叉树(递归)_多叉树的合并_TABE_的博客-程序员秘密

注:题目:给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。示例 1:输入: Tree 1 Tree 2 1 2

axio使用get方法之传递对象数组问题及解决方法_axios get传递对象_DuebassLei的博客-程序员秘密

axios的get方法传递对象数组问题描述解决办法问题描述使用axios发送get请求,传递参数如下格式:const params = { filter: [{ property: 'optionTypeId', operator: 'eq', value:'TYPE10' }] }发送请求后,发现请求失败,查看控制台参数为

MIPI参数配置解释_mipi 必要参数_406不速之客的博客-程序员秘密

1、LCD显示单位:帧(1)显示器上一整个画面的内容成为一个帧,整个显示器工作是一帧一帧的在显示。(2)电源实际就是以每秒种24帧的速度在播放图片。(3)帧内数据:一帧分为多行,一行分为多像素,因此一帧图像其实就是多个像素组成的矩阵。(4)帧外数据:整个视频由很多个帧构成,最终播放视频时逐个播放各个图像帧即可。2、LCD显示一帧图像的过程(1)首先把帧分为行,然后再把行分为...

随便推点

9月份GitHub上最热门的Python项目_码农职场的博客-程序员秘密

 上次小泽给大家介绍了9月份GitHub上star最多的java开源项目,这次我们就和大家介绍下 GitHub 上 最受欢迎的 11 个Python开源项目,看看在这些项目中,你有在用或用过哪些呢?1、Pythonhttps://github.com/TheAlgorithms/Python用Python实现的所有算法,不过创建者表示这些仅用于演示目的。Python标准库中有许多种...

php mysql 导出 csv_php如何快速导出数据库到csv(代码实现)_孫志貴的博客-程序员秘密

本篇文章给大家带来的内容是关于php如何快速导出数据库到csv(代码实现),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。需求需要在浏览器页面,通过下载按钮将数据库全部导出到本地.方案每读一行数据库记录,echo一行到输出;实现//导出函数,参数$mycli已打开数据库的mycli对象function exportDbTable($mysqi){//首先输出头部header("Co...

华为瘦胖ap互转_想问一下,怎么把华为的胖瘦Ap一体机从瘦AP转换成胖Ap模式呢?..._weixin_39946460的博客-程序员秘密

展开全部以AP3010DN-AGN为例瘦模式转换为胖模式1 待AP启动完成后,从console口登录,e5a48de588b662616964757a686964616f31333433616162波特率为9600,账号默认为admin,密码为[email protected];2 登录成功后,AP默认的IP地址为169.254.1.1/16;我们可以将电脑的IP设置成同网段的IP,比如169.25...

Spring中Elasticsearch使用Spel动态创建Documet类的Index_dothetrick的博客-程序员秘密

1 使用场景在一些项目中,需要在程序中根据条件,动态生成es的index,达到整理数据的目的。例如,大数据量的系统日志,需要按天分index,这时就需要动态生成Index。2 Spel动态生成Index这里使用spring-data-elasticsearch的ElasticsearchRestTemplate操作es,版本为3.2.0。<dependency> <groupId>org.springframework.data</groupId> <

Nginx中变量的实现(下)_deyimasf的博客-程序员秘密

这是Nginx中变量的实现下篇,上篇可以点这里  1.初始化变量    尽管是同一个变量,但在定义和索引的时候nginx会创建两个ngx_http_variable_t结构体,然后分别存在于两个不同的容器中。一般情况下定义变量的时候该变量携带的信息更全,而索引变量时则相对少一些。    初始化变量的过程其实就是两个容器融合的过程,这个过程在nginx中对应ngx_http_vari...

金庸的博士后入学考试题目_dizi9750的博客-程序员秘密

一、选择题 ◎ 单选   1、蓝凤凰及其诸位女弟子通过水蛭将血输到令狐冲体内,你可以得到以下那种推 测:   a、令狐冲为ab型血,蓝凤凰及其弟子为a、b、或ab型   b、令狐冲为b型血,蓝凤凰及其弟子为ab、b或o型   c、令狐冲为o型血,蓝凤凰及其弟子为a、b或o型   d、令狐冲为a型血,蓝凤凰及其弟子为ab或o型   e、以上推测都不对 ...

推荐文章

热门文章

相关标签