Python自动化小技巧18——自动化资产月报(word设置字体表格样式,查找替换文字)

案例背景

每月都要写各种月报,经营管理月报,资产月报.....这些报告文字目标都是高度相似的,只是需要替换为每个月的实际数据就行,如下:

 

(打码是怕信息泄露.....)

可以看到,这个报告的都是高度模板化,我们只需要对里面的某些文字进行替换,例如2023年7月换成2023年8月,资产数量490替换为最新的值,表格里面的数值也是一样的情况。

这篇文章的目的:我们并不是从头到尾,去从0开始生产月报,而是在往期的月报上进行修改。

这些东西都是复制粘贴,数据准备好了,按照定点的位置填就行了。所以代码来自动化这个流程就很变得很便捷。


代码实现

导入包:

import xlrd
import pandas as pd

import docx
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
from docx import Document
from docx.oxml.ns import qn
import calendar
from docx.shared import Cm, Pt #设置像素、缩进等
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT

year = 2023
month = 7
num_days = calendar.monthrange(year, month)[1]
print(f"{year}年{month}月有{num_days}天")

 这里我们要先填入年份和信息,因为月报是月底写,最后的日期可能是31号可能是30号,所以需要用代码自动化计算一下日期.....


锚点查找

进行我们的第一步,我们需要数据来写报告,数据肯定都在excel里面算好了,没算好也肯定需要一定的流程加工算好了再说.....(参考我自动化小技巧16的文章)

例如上面我展示的目标,我需要填资产和负债的信息,这些数据都在财务那边给我的资产负债表里面,我肯定不会自己去打开excel表查找我要的值然后再写入代码里面.....这太低效了,而且这就不是自动化了。我们要用代码来找。

但是怎么找自己特定需要的数据呢?例如我要找流动资产合计这一项,我可以用固定的位置来找,比如财务那边总把流动资产合计的值写在C26这个格子里面。

 但这种固定位置的查找可能有时候会有问题,比如财务那边突然需要加个标题,把资产负债表整体向下挪动了一行....那么C26这个位置就不对了。

所以绝对位置不准确,那我们就应该用相对位置,例如我发现我需要的这个值总是在‘流动资产合计’这个格子的右边两列的位置。那我先查找‘流动资产合计’这一项,然后右移动两格就是我需要的值了。

我称这种查找为锚定查找,找一个锚点,然后偏移找到自己需要的附近的值。这种相对查找的方法比绝对查找的方法出问题的可能性会小一点。

读取资产负债表,定义一个函数来进行锚点查找:

#资产负债表
wb = xlrd.open_workbook('*************业有限公司2023年7月报表20230731.xls')
sheet = wb.sheet_by_index(0)   #wb.sheet_by_name('资产负债表')
def find_and_offset_xlrd(sheet, target_value, offset_row, offset_column):
    for row in range(sheet.nrows):
        for col in range(sheet.ncols):
            if str(sheet.cell(row, col).value).replace(' ','') == target_value:
                target_cell_value = sheet.cell(row + offset_row, col + offset_column).value
                return target_cell_value

然后进行查找各种我们需要的值:(注意这个函数是针对xls文件的,xlsx文件读取不了。。后面还会有针对xlsx的锚点查找函数,放在文章最后)

资产总计 = find_and_offset_xlrd(sheet, '资产总计', 0, 2)/10000
流动资产合计=find_and_offset_xlrd(sheet, '流动资产合计', 0, 2)/10000
非流动资产合计=find_and_offset_xlrd(sheet, '非流动资产合计', 0, 2)/10000
负债合计=find_and_offset_xlrd(sheet, '负债合计', 0, 2)/10000
固定资产净值=find_and_offset_xlrd(sheet, '固定资产净值', 0, 2)/10000
[资产总计,流动资产合计,非流动资产合计,负债合计,固定资产净值]

 这就是我们需要的值,然后进行一些必要的运算

流动资产占比=100*流动资产合计/资产总计
非流动资产占比=100*非流动资产合计/资产总计
净资产=资产总计-负债合计
固定资产占比=100*固定资产净值/资产总计
其他非流动资产=非流动资产合计-固定资产净值
其他非流动资产占比=100*其他非流动资产/资产总计

段落替换

由于我们是资产月报,还得往表格里面填入各种资产的信息,我们需要读取我之前文章做好的资产分类汇总表:

df=pd.read_excel('../../资产管理/资产类别变动后汇总/分类汇总金额.xlsx',sheet_name='汇总').set_index('资产类别名称')
df

 进行一些必要的计算...:

实物资产数量=df.loc['合计','资产数量']
资产原值=df.loc['合计','原值']/10000
生产及动力设备=df.loc['生产及动力设备','原值']/10000

写好我们 需要的文字目标:

txt=f'''截至{year}年{month}月,**公司资产总计约{资产总计:.0f}万元。其中,流动资产{流动资产合计:.0f}万元,占比{流动资产占比:.1f}%;非流动资产{非流动资产合计:.0f}万元,占比{非流动资产占比:.1f}%。负债合计{负债合计:.0f}万元,净资产{净资产:.0f}万元。
公司非流动资产中,固定资产{固定资产净值:.0f}万元(固定资产净值),占资产总额{固定资产占比:.0f}%;其他类非流动资产{其他非流动资产:.0f}万元,占资产总额{其他非流动资产占比:.2f}%(长期待摊费用、递延所得税资产、无形资产)。
截至{year}年{month}月,**公司管理实物资产数量{实物资产数量:.0f}项,金额{资产原值:.0f}万元(资产原值)。其中,自有实物资产数量{实物资产数量:.0f}项,主要为机械设备,账面价值{生产及动力设备:.0f}万元;受托管理实物资产数量0项,账面价值(或资产原值)0万元。公司管理实物资产情况如下表:
'''
txt=txt.split('\n')

这几句话我们就需要进行替换了,替换掉原来的段落。这种很多需要修改的我们就进行段落替换,如果只是像2023年7月换成8月的这种小修改就简单替换(后面会有这种函数)

核心函数!!修改样式:

def set_style(paragraphs,style=u'仿宋_GB2312',size=16):
    for run in paragraphs.runs:
        run.font.name = style
        run.font.size = Pt(size)
        r = run._element.rPr.rFonts
        r.set(qn("w:eastAsia"),style)

这个函数的功能是修改这个段落的字体和大小。因为我发现每次代码修改了word里面的东西后,它就会默认使用微软体文字.....使用我们需要把内容变成我们要的模板格式。我们需要这个函数,无论替换了什么内容,都需要它来变一下格式 擦屁股。

读取文档,替换文字:

doc = docx.Document(f'./资产附件/附件1:资产管理月度情况简报{month-1}月.docx')
for i,paragraph in enumerate(doc.paragraphs):
    #if '2023年' in run.text:
        
    if '月,远大公司资产总计约'in paragraph.text:
        paragraph.text =txt[0]
        print('0')   ; set_style(paragraph)
    if '公司非流动资产中,固定资产' in paragraph.text:
        paragraph.text = txt[1]
        print('1')  ;set_style(paragraph)
    if '月,远大公司管理实物资产数量' in paragraph.text:
        paragraph.text=txt[2]
        print('2')      ;set_style(paragraph)  
    if f'{year}年' in paragraph.text and (i>len(doc.paragraphs)-3):
        paragraph.text=f'{year}年{month}月{num_days}日'    ;set_style(paragraph)
        paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT

if判断是尽可能找到你需要替换的段落,然后换为上面我们设定的文字,然后设置一下样式。

最后这个条件判断意思是:如果段落行数为最后3行里面的出现了年月日,那么久换为最新的年月日。因为我需要改落款日期,但是对全文全部修改会可能出问题,所以限定了最后3行。


文字替换

这个函数类似于word里面的替换功能,把你要查找的文字,换为其他文字

#查找替换
def docx_replace(old_text, new_text, doc):
    for paragraph in doc.paragraphs:
        if old_text in paragraph.text:
            paragraph.text = paragraph.text.replace(old_text, new_text)
            set_style(paragraph)
docx_replace(f"截至{year}年{month-1}月", f"截至{year}年{month}月", doc)

 这是替换了月份,每次都把月报里面的日期肯定要更新为最新的。

docx_replace(f"{year}年1-{month-1}月,经省", f"{year}年1-{month}月,经省", doc)
docx_replace(f"现将**公司{month-1}月资产管理情况报告如下", f"现将**公司{month}月资产管理情况报告如下", doc)

表格替换

文字我们都改了之后,我们对word表里面的数据也要进行修改:

我们可以获取word里面的表对象:

table = doc.tables[0]

直接替换里面的文字是不行的,还是因为样式会变成默认样式,和领导要求的模板不一样...

所以也需要设置一下。

定义一个表格替换函数,传入你要替换的格子,替换的文本,以及字体样式,大小,居中什么的

def set_cell_text(cell, text, font_name='仿宋_GB2312', font_size=12, alignment=WD_PARAGRAPH_ALIGNMENT.CENTER):
    cell.text = text
    for paragraph in cell.paragraphs:
        paragraph.alignment = alignment
        set_style(paragraph,font_name,font_size)

 因为目标表格填的位置是固定的,所以我可以使用绝对位置来查找我需要换的数值:

set_cell_text(table.cell(2, 3), str(df.loc['房屋建筑物','资产数量']), '仿宋_GB2312', 12)
set_cell_text(table.cell(2, 4), f'''{df.loc['房屋建筑物','原值']/10000:.0f}''')

set_cell_text(table.cell(7, 3), str(df.loc['办公及电子设备','资产数量']))
set_cell_text(table.cell(7, 4), f'''{df.loc['办公及电子设备','原值']/10000:.0f}''')

set_cell_text(table.cell(8, 3), str(df.loc['车辆','资产数量']))
set_cell_text(table.cell(8, 4), f'''{df.loc['车辆','原值']/10000:.0f}''')

set_cell_text(table.cell(9, 3), str(df.loc['生产及动力设备','资产数量']))
set_cell_text(table.cell(9, 4), f'''{df.loc['生产及动力设备','原值']/10000:.0f}''')

set_cell_text(table.cell(10, 3), str(df.loc['安全设施','资产数量']))
set_cell_text(table.cell(10, 4), f'''{df.loc['安全设施','原值']/10000:.0f}''')

set_cell_text(table.cell(11, 3), str(df.loc['家具和其他','资产数量']))
set_cell_text(table.cell(11, 4), f'''{df.loc['家具和其他','原值']/10000:.0f}''')

set_cell_text(table.cell(15, 3), str(df.loc['合计','资产数量']))
set_cell_text(table.cell(15, 4), f'''{df.loc['合计','原值']/10000:.0f}''')

最后保存,一个自动化月报的工程就完成啦。

doc.save(f'附件1:资产管理月度情况简报{month}月.docx')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/83518.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 线程安全

一、线程安全的概念 线程安全即就是在多线程运行的时候,不论线程的调度顺序怎样,最终的结果都是 一样的、正确的。那么就说这些线程是安全的。 二、如何保证线程安全 1.线程同步 保证同一时刻只有一个线程访问临界资源。线程同步的方法有4种&#xf…

python中使用xml快速创建Caption和URL书签管理器应用程序

导语: 本文介绍如何使用wxPython库创建一个Caption和URL管理器应用程序。该应用程序具有图形用户界面,允许用户输入Caption和URL,并将其保存到XML文件中。此外,还提供了浏览文件夹并选择HTML文件的功能,并可以运行另一…

低代码开发 轻松解决企业数字化能力建设困局

谈及数字化,这是一个几乎所有领域都在使用的概念。当下,数字化正在经历从以企业为中心向产业为中心转移、从追求效能为主的价值诉求向追求业务创新和业务发展的价值诉求转变,不断增加的不确定性也为数字化的发展蒙上了一层阴影。 除了企业自…

基于Spring Boot的机场VIP客户管理系统的设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频: 基于Spring Boot的机场VIP客户管理系统的设计与实现(Javaspring bootMySQL) 使用技术: 前端:html css javascript jQuery ajax thymeleaf 微信小程序 后端:Java s…

数据结构作业——哈夫曼树

/*【基本要求】 (1) 从文件中读出一篇英文文章,包含字母和空格等字符。 (2) 统计各个字符出现的频度。 (3) 根据出现的频度,为每个出现的字符建立一个哈夫曼编码,并输出。…

深入源码分析kubernetes informer机制(二)Reflector

[阅读指南] 这是该系列第二篇 基于kubernetes 1.27 stage版本 为了方便阅读,后续所有代码均省略了错误处理及与关注逻辑无关的部分。 文章目录 Reflector是什么整体结构工作流程list拉取数据缓存resync操作watch监听操作 总结 Reflector是什么 reflector在informer…

爬虫逆向实战(七)--猿人学第十六题

一、数据接口分析 主页地址:猿人学第十六题 1、抓包 通过抓包可以发现数据接口是api/match/16 2、判断是否有加密参数 请求参数是否加密? 通过查看“载荷”模块可以看出m是加密参数 请求头是否加密? 无响应是否加密? 无cook…

云聊天项目测试

前言 以下将对云聊天项目编写测试用例以及主要功能的自动化测试。 1. 测试用例的编写 2. 自动化测试 以下进行部分自动化测试用例的执行,检验项目功能是否符合预期。 2.1 登录功能测试 测试代码: 输入非法用户名或密码逻辑相似,不重复描…

安防监控视频汇聚平台EasyCVR视频平台调用iframe地址无法播放的问题解决方案

安防监控视频汇聚平台EasyCVR基于云边端一体化架构,具有强大的数据接入、处理及分发能力,可提供视频监控直播、云端录像、视频云存储、视频集中存储、视频存储磁盘阵列、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、AI算法中台智能分析无缝…

冷冻冷藏自动化立体库|HEGERLS四向穿梭车助力打造冷链智能仓储新力量

随着中国仓储物流整体规模和低温产品消费需求的稳步增长,冷链市场应用潜力不断释放。而在实际运行中,由于冷库容量不足、基础设施落后、管理机制欠缺等原因,经常出现“断链”现象,严重威胁到产品质量和消费者安全。 河北沃克金属…

React Native expo项目修改应用程序名称

https://expo.dev/accounts/xutongbao/projects npm install --global eas-cli && \eas init --id e32cf2c0-da5b-4a65-814a-4958d58f0ca7 eas init --id e32cf2c0-da5b-4a65-814a-4958d58f0ca7 app.config.js: export default {name: 学习,slug: learn-gpt,owner: x…

Comparable和Comparator区别

Comparable和Comparator接口都是实现集合中元素的比较、排序的,众所周知,诸如Integer,double等基本数据类型,java可以对他们进行比较,而对于类的比较,需要人工定义比较用到的字段比较逻辑。总体来讲&#x…

【微服务技术二】Feign、Gateway(路由、过滤器、跨域)的初步认知

微服务技术二 五、Feign远程调用Feign替代RestTemplate自定义Feign配置方式一:配置文件方式:方式二:java代码方式 Feign性能优化Feign的最佳实践* 六、Gateway网关搭建网关服务路由断言工厂Route Predicate Factory路由过滤器 GatewayFilter默…

负载均衡下的 WebShell 连接

目录 负载均衡简介负载均衡的分类网络通信分类 负载均衡下的 WebShell 连接场景描述难点介绍解决方法**Plan A** **关掉其中一台机器**(作死)**Plan B** **执行前先判断要不要执行****Plan C** 在Web 层做一次 HTTP 流量转发 (重点&#xff0…

排名前 6 位的数学编程语言

0 说明 任何对数学感兴趣或计划学习数学的人,都应该至少对编程语言有一定的流利程度。您不仅会更有就业能力,还可以更深入地理解和探索数学。那么你应该学习什么语言呢? 1.python 对于任何正在学习数学的人来说,Python都是一门很棒…

vue所有UI库通用)tree-select 下拉多选(设置 maxTagPlaceholder 隐藏 tag 时显示的内容,支持鼠标悬浮展示更多

如果可以实现记得点赞分享,谢谢老铁~ 1.需求描述 引用的下拉树形结构支持多选,限制选中tag的个数,且超过制定个数,鼠标悬浮展示更多已选中。 2.先看下效果图 3.实现思路 首先根据API文档,先设置maxTagC…

LVS-DR+keepalived实现高可用负载群集

VRRP 通信原理: VRRP就是虚拟路由冗余协议,它的出现就是为了解决静态路由的单点故障。 VRRP是通过一种竞选的一种协议机制,来将路由交给某台VRRP路由。 VRRP用IP多播的方式(多播地址224.0.0.18)来实现高可用的通信&…

Redis中的有序集合

前言 本文着重介绍Redis中的有序集合的底层实现中的跳表 有序集合 Sorted Set Redis中的Sorted Set 是一个有序的无重复值的集合,他底层是使用压缩列表和跳表实现的,和Java中的HashMap底层数据结构(1.8)链表红黑树异曲同工之妙…

记一次mysql8 在linux上安装全过程

参照MYSQL官网官方文档安装 1、mysql官网 mysql官网 2、直接进入文档页 找到安装文档 3、找到自己系统对应的安装文档,选合适的安装方式,我这里使用的是YUM方式 a、开始安装之前需要替换yum仓库 具体步骤如下 b、将下载的文件上传至自己的服务器 如下…

什么是原型(prototype)和原型链(prototype chain)?如何继承一个对象的属性和方法?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 原型(Prototype)和原型链(Prototype Chain)⭐ 原型(Prototype)⭐ 原型链(Prototype Chain)⭐ 继承属性和方法⭐ 写在最后 ⭐ 专栏简介 前端入…