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

news2025/1/22 16:54:53

案例背景

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

 

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

可以看到,这个报告的都是高度模板化,我们只需要对里面的某些文字进行替换,例如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')

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浏览器 - 事件循环机制详解

目录 1,浏览器进程模型进程线程浏览器的进程和线程1,浏览器进程2,网络进程3,渲染进程 2,渲染主线程事件循环异步同步 JS 为什么会阻塞渲染任务优先级 3,常见面试题1,如何理解 js 的异步2&#x…

时序预测 | MATLAB实现基于KNN K近邻的时间序列预测-递归预测未来(多指标评价)

时序预测 | MATLAB实现基于KNN K近邻的时间序列预测-递归预测未来(多指标评价) 目录 时序预测 | MATLAB实现基于KNN K近邻的时间序列预测-递归预测未来(多指标评价)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 基于KNN K近邻的时间序列预测-递归预测未来(多指标评价) …

数据集成与流动优化:解锁企业数据的无限潜力

在当今数字化时代,企业拥有海量数据,这些数据散落在不同部门、系统和平台之间,形成了所谓的“数据孤岛”。要想实现数据的最大化价值,就必须解决数据集成与流动的挑战。本文将深入探讨数据集成与流动优化的重要性,以及…

833-字符串中查找与替换

题目描述: 你会得到一个字符串 s (索引从 0 开始),你必须对它执行 k 个替换操作。替换操作以三个长度均为 k 的并行数组给出:indices, sources, targets。 要完成第 i 个替换操作: 检查 子字符串 sources[i] 是否出现在 原字符串 s 的索…

POSTGRESQL 关于安装中自动启动的问题 详解

开头还是介绍一下群,如果感兴趣Polardb ,mongodb ,MySQL ,Postgresql ,redis ,SQL SERVER ,ORACLE,Oceanbase 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请加 liuaustin3微信号 &…

使用SpringBoot + Thymeleaf 完成简单的用户登录

😀前言 本篇博文是关于Thymeleaf 的综合案例, 使用SpringBoot Thymeleaf 完成简单的用户登录-列表功能,希望你能够喜欢😊 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨…

数据结构--最短路径 Floyd算法

数据结构–最短路径 Floyd算法 F l o y d 算法:求出每⼀对顶点之间的最短路径 \color{red}Floyd算法:求出每⼀对顶点之间的最短路径 Floyd算法:求出每⼀对顶点之间的最短路径 使⽤动态规划思想,将问题的求解分为多个阶段 对于n个顶…

re学习(31)BUUCTF-xx(多层加密)

参考文章:【BUUCTF逆向 [2019红帽杯]xx】_nb_What_DG的博客-CSDN博客 re学习笔记(26)BUUCTF-re-[2019红帽杯]xx_Forgo7ten的博客-CSDN博客 还有B站 水番正文 IDA64位载入 shiftF12查看字符串 交叉引用找到关键代码 使用findcrypt插件找到…

H13-922题库 HCIP-GaussDB-OLAP V1.5

**H13-922 V1.5 GaussDB(DWS) OLAP题库 华为认证GaussDB OLAP数据库高级工程师HCIP-GaussDB-OLAP V1.0自2019年10月18日起,正式在中国区发布。当前版本V1.5 考试前提: 掌握基本的数据库基础知识、掌握数据仓库运维的基础知识、掌握基本Linux运维知识、…

互联网发展历程:速度与效率,交换机的登场

互联网的演进就像一场追求速度与效率的竞赛,每一次的技术升级都为我们带来更快、更高效的网络体验。然而,在网络的初期阶段,人们面临着数据传输速度不够快的问题。一项关键的技术应运而生,那就是“交换机”。 速度不足的困境&…

SpringBoot + Mybatis多数据源

一、配置文件 spring: # datasource: # username: root # password: 123456 # url: jdbc:mysql://127.0.0.1:3306/jun01?characterEncodingutf-8&serverTimezoneUTC # driver-class-name: com.mysql.cj.jdbc.Driverdatasource:# 数据源1onedata:jdbc-url: j…

希尔排序【Java算法】

文章目录 1. 概念2. 思路3. 代码实现 1. 概念 希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。希尔排序在数组中采用跳跃式分组的策略,通过某个增量将数组元素划分为若干组,然后分…

linux学习(自写shell)[11]

打印出提示信息获取用户键盘输入 cmd_line[NUM];用来保存完整的命令行 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/wait.h>#define NUM 1024 char cmd_line[NUM]; //shell int main() {wh…

AI Chat 设计模式:15. 桥接模式

本文是该系列的第十五篇&#xff0c;采用问答式的方式展开&#xff0c;问题由我提出&#xff0c;答案由 Chat AI 作出&#xff0c;灰色背景的文字则主要是我的一些思考和补充。 问题列表 Q.1 如果你是第一次接触桥接模式&#xff0c;那么你会有哪些疑问呢&#xff1f;A.1Q.2 什…

FreeRTOS(独立看门狗监测任务执行与低功耗Tickless模式)

资料来源于硬件家园&#xff1a;资料汇总 - FreeRTOS实时操作系统课程(多任务管理) 目录 一、独立看门狗介绍 二、看门狗监测多任务执行思路 1、监测目标 2、监测方案 3、应用注意事项 三、看门狗监测多任务编程 1、STM32cubeMX配置 2、代码编写 四、低功耗Tickless模…

QT笔记——QProcess学习

我们常常想通过某一个类&#xff0c;来启动一个外部进程 本文将讲解如何通过QProcess来进行启动外部进程 一&#xff1a;了解QProcess QProcess是Qt框架提供的一个类&#xff0c;用于在应用程序中执行外部进程。它提供了一系列函数来启动、控制和与外部进程进行交互 1.启动进程…

02 基于51单片机的LED闪烁实验

目录 前言 一、整体目录结构 二、代码展示 三、main.c代码解析 四、下载到单片机中 总结 前言 前面我们已经学会了点亮一个led的实验&#xff0c;今天我们来实现LED闪烁。前面我们讲到想要让LED亮的话&#xff0c;只要给单片机引脚高电平就好了&#xff0c;如果给LED低电平的话…

Flink之Task解析

Flink之Task解析 对Flink的Task进行解析前,我们首先要清楚几个角色TaskManager、Slot、Task、Subtask、TaskChain分别是什么 角色注释TaskManager在Flink中TaskManager就是一个管理task的进程,每个节点只有一个TaskManagerSlotSlot就是TaskManager中的槽位,一个TaskManager中可…

Vue2-配置脚手架、分析脚手架、render函数、ref属性、props配置项、mixin配置项、scoped样式、插件

&#x1f954;:总有一段付出了没有回报的日子 是在扎根 更多Vue知识请点击——Vue.js VUE2-Day6 配置脚手架脚手架结构render函数vue.js与vue.runtime.xxx.js的区别引入render函数为什么要引入残缺的vue呢&#xff1f; 脚手架默认配置ref属性props配置项传递数据接收数据注意点…

elementui form组件出现英文提示

今天让解决一个bug&#xff0c;是表单组件提示词会出现英文。 问题情景如下&#xff1a; 有时会出现中文&#xff0c;有时会出现英文。 解决方法&#xff1a; 经查看&#xff0c;代码采用的是elementui的form组件&#xff0c;在el-form-item中使用了required属性&#xff0c;同…