技术标签: python reportlab 正则表达式 PyPDF2 Python
博客主页:https://tomcat.blog.csdn.net
博主昵称:农民工老王
主要领域:Java、Linux、K8S
期待大家的关注点赞收藏留言
我们部门偶尔加班,领导让我统计同事们的加班情况,并处理加班餐的报销工作,其中比较麻烦的一个事情是整理发票,我们公司对电子发票的要求是:
每月有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;人员-老王,肖美女,兵哥,阿杜,老李,老荣,涛哥,杰哥,核姐,老姚,追风少年 |
# ------------------------------------------
# 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 。
文章浏览阅读166次。Redis 命令Redis 命令用于在 redis 服务上执行操作。要在 redis 服务上执行命令需要一个 redis 客户端。Redis 客户端在我们之前下载的的 redis 的安装包中。语法Redis 客户端的基本语法为:$ redis-cli实例以下实例讲解了如何启动 redis 客户端:启动 redis 客户端,打开终端并输入命令 redis-cli。该命
文章浏览阅读372次。个人笔记
文章浏览阅读955次。POJ 2965 The Pilots Brothers' refrigerator (枚举)
文章浏览阅读1.5k次。信驰达蓝牙模组信驰达透传固件功能特点:使用简单,无需任何蓝牙协议栈应用经验;支持蓝牙 5.0 协议栈。价格便宜,价格便宜,价格便宜 (重要的事情只说三遍)1. 环境准备1.1 硬件环境USB转TTL 1个 + 杜邦线 6 根RSBRS02ABR 模块 1个 1.2软件准备准备驱动安装包CP210x_Universal_Windows_Driver:准备串口调试助手工具UartAssist : 下载链接准备手机APP:nRf-Connect _蓝牙5.0能被串口助手检测到吗
文章浏览阅读1.1k次,点赞2次,收藏8次。前言你是否觉得自己从学校毕业的时候只做过小玩具一样的程序?走入职场后哪怕没有什么经验也可以把以下这些课外练习走一遍(朋友的抱怨:学校课程总是从理论出发,作业项目都看不出有什么实际作用,不如从工作中的需求出发)建议:不要乱买书,不要乱追新技术新名词,基础的东西经过很长时间积累而且还会在未来至少10年通用。回顾一下历史,看看历史上时间线上技术的发展,你才能明白明天会是什么样。一
文章浏览阅读2.1w次,点赞19次,收藏58次。作者:计算机的潜意识在本篇文章中,我将对机器学习做个概要的介绍。本文的目的是能让即便完全不了解机器学习的人也能了解机器学习,并且上手相关的实践。这篇文档也算是 EasyPR开发的番外篇,从这里开始,必须对机器学习了解才能进一步介绍EasyPR的内核。当然,本文也面对一般读者,不会对阅读有相关的前提要求。在进入正题前,我想读者心中可能会有一个疑惑:机器学习有什么重要性,以至于要阅读完
文章浏览阅读1.2w次,点赞15次,收藏14次。IDEA异常 cannot resolve symbol ‘HttpServletRequest’如图一在IDEA出现的问题,java编辑器找不到HttpServletRequest包,只需将tomcat中的库倒进来即可如图二。步骤file->project structure->modules->选择对应的项目->dependencies->右侧加号libraries->添加tomcat的libr
文章浏览阅读3k次。拦截器是动态拦截Action调用的对象.它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行.同时也是提供了一种可以提取action中可重用的部分的方式.拦截器必须是无状态的,不能保证为每一个请求或者action创建一个实例.拦截器可以选择短路一个action调用,然后返回一个结果码(如com.opensymphony.xwork_interceptors
文章浏览阅读5k次,点赞2次,收藏26次。目前看了两篇论文总结一下:DS-SLAM A Semantic Visual SLAM towards dynamic environments (2018):这篇文章基于ORB_SLAM2, 利用帧间图像的光流跟踪,进行一致性检验(利用了基础矩阵,判断点极线距离的大小),找到运动的像素点。同时另开辟一个线程做Segmet 场景语义分割(只能分割20种物体),认为人是可能运动的物体,如果运动的..._视觉slam怎么去除动态特征点
文章浏览阅读722次。Bellman-Ford算法和Dijkstra算法都是求解图的最短路径的算法。Bellman是求单源点到各个顶点的最短路径,适用条件为有向或无向图,权重可为负值。当存在负权环路时,算法返回一个false值。该算法效率比较低,需要对边进行 |V|- 1 次松弛操作Bellman-Ford算法寻找单源最短路径的时间复杂度为O(V*E)。(V为给定图的顶点集合,E为给定图的边集合)两者区别在于:..._sssp
文章浏览阅读1.7k次。vm oracle linux7 安装 Oracle E-Business 12.1说明:在执行下面步骤之前,需要提前申请oracle账号,下载12.1介质。注册oracle账号链接:http://metalink.oracle.com/oracle linux7 和Oracle E-Business 12.1下载链接:https://edelivery.oracle.com文章目录vm oracle linux7 安装 Oracle E-Business 12.1一、操作系统要求1.1、在 v_ins-32016
文章浏览阅读572次。_今天的作业,自己绘制第二章有理数的思维导图,发到老师的作业小程序