快速生成定制化的Word文档:Python实践指南
前言
众所周知,安服工程师又叫做Word工程师,在打工或者批量SRC的时候,如果产出很多,又需要一个一个的写报告的情况下会非常的折磨人,因此查了一些相关的资料,发现使用python的docxtpl库批量写报告效果很不错,记录一下。
介绍
docxtpl是一个用于生成 Microsoft Word 文档的模板引擎库,它结合了 docx 模块和 Jinja2 模板引擎,使用户能够使用 Microsoft Word 模板文件并在其中填充动态数据。它提供了一种方便的方式来生成个性化的 Word 文档,并支持条件语句、循环语句和变量等控制结构,以满足不同的文档生成需求。
(资料图片)
官方GitHub地址:https://github.com/elapouya/python-docx-template
官方文档地址:https://docxtpl.readthedocs.io/en/latest/
安装:
pip3 install docxtpl
基础使用
from docxtpl import DocxTemplatedoc = DocxTemplate("test.docx")context = {"whoami": "d4m1ts"}doc.render(context)doc.save("generated_doc.docx")
其中,test.docx内容如下:
生成后的结果如下:
案例介绍
需求假设
写一份不考虑美观的漏扫报告,需要有统计结果图和漏洞详情,每个漏洞包括漏洞名、漏洞地址、漏洞等级、漏洞危害、复现过程、修复建议六个部分。
模板文档准备
编写的模板文档如下,使用到了常见的if、for、赋值等,保存为template.docx(点击可下载),后续只需要向里面填充数据即可。
template
数据结构分析
传入数据需要一串json字符串,因此我们根据模板文档梳理好json结构,然后传入即可。
梳理好的数据结构如下:
{ "饼图": "111", "柱状图": "222", "漏洞简报": [ { "漏洞名": "测试漏洞名1", "漏洞等级": "高危" } ], "漏洞详情": [ { "漏洞名": "测试漏洞名1", "漏洞地址": "http://blog.gm7.org/", "漏洞等级": "高危", "漏洞危害": "危害XXX", "复现过程": "先xxx,再xxx,最后xxx", "修复建议": "更新到最新版本即可" } ]}
编写代码测试一下可行性:
from docxtpl import DocxTemplatedoc = DocxTemplate("template.docx")context = { "饼图": "111", "柱状图": "222", "漏洞简报": [ { "漏洞名": "测试漏洞名1", "漏洞等级": "高危" }, { "漏洞名": "测试漏洞名2", "漏洞等级": "严重" }, { "漏洞名": "测试漏洞名2", "漏洞等级": "中危" } ], "漏洞详情": [ { "漏洞名": "测试漏洞名1", "漏洞地址": "http://blog.gm7.org/", "漏洞等级": "高危", "漏洞危害": "危害XXX", "复现过程": "先xxx,再xxx,最后xxx", "修复建议": "更新到最新版本即可" }, { "漏洞名": "测试漏洞名2", "漏洞地址": "http://bblog.gm7.org/", "漏洞等级": "严重", "漏洞危害": "危害XXX", "复现过程": "先xxx,再xxx,最后xxx", "修复建议": "更新到最新版本即可" }, { "漏洞名": "测试漏洞名3", "漏洞地址": "http://cblog.gm7.org/", "漏洞等级": "中危", "漏洞危害": "危害XXX", "复现过程": "先xxx,再xxx,最后xxx", "修复建议": "更新到最新版本即可" } ] }doc.render(context)doc.save("generated_doc.docx")
很好,达到了预期的效果。
res
加入图表
在上面的过程中,内容几乎是没问题了,但是图表还是没有展示出来。生成图表我们使用plotly这个库,并将生成内容写入ByteIO。
相关代码如下:
import plotly.graph_objects as gofrom io import BytesIOdef generatePieChart(title: str, labels: list, values: list, colors: list): """ 生成饼图 https://juejin.cn/post/6911701157647745031#heading-3 https://juejin.cn/post/6950460207860449317#heading-5 :param title: 饼图标题 :param labels: 饼图标签 :param values: 饼图数据 :param colors: 饼图每块的颜色 :return: """ # 基础饼图 fig = go.Figure(data=[go.Pie( labels=labels, values=values, hole=.4, # 中心环大小 insidetextorientation="horizontal" )]) # 更新颜色 fig.update_traces( textposition="inside", # 文本显示位置 hoverinfo="label+percent", # 悬停信息 textinfo="label+percent", # 饼图中显示的信息 textfont_size=15, marker=dict(colors=colors) ) # 更新标题 fig.update_layout( title={ # 设置整个标题的名称和位置 "text": title, "y": 0.96, # y轴数值 "x": 0.5, # x轴数值 "xanchor": "center", # x、y轴相对位置 "yanchor": "top" } ) image_io = BytesIO() fig.write_image(image_io, format="png") return image_iodef generateBarChart(title: str, x: list, y: list): """ 生成柱状图 https://cloud.tencent.com/developer/article/1817208 https://blog.csdn.net/qq_25443541/article/details/115999537 https://blog.csdn.net/weixin_45826022/article/details/122912484 :param title: 标题 :param x: 柱状图标签 :param y: 柱状图数据 :return: """ # x轴长度最为18 b = x x = [] for i in b: if len(i) >= 18: x.append(f"{i[:15]}...") else: x.append(i) # 基础柱状图 fig = go.Figure(data=[go.Bar( x=x, y=y, text=y, textposition="outside", marker=dict(color=["#3498DB"] * len(y)), width=0.3 )]) # 更新标题 fig.update_layout( title={ # 设置整个标题的名称和位置 "text": title, "y": 0.96, # y轴数值 "x": 0.5, # x轴数值 "xanchor": "center", # x、y轴相对位置 "yanchor": "top" }, xaxis_tickangle=-45, # 倾斜45度 plot_bgcolor="rgba(0,0,0,0)" # 背景透明 ) fig.update_xaxes( showgrid=False ) fig.update_yaxes( zeroline=True, zerolinecolor="#17202A", zerolinewidth=1, showgrid=True, gridcolor="#17202A", showline=True ) image_io = BytesIO() fig.write_image(image_io, format="png") return image_io
最终结果
要插入图片内容,代码语法如下:
myimage = InlineImage(tpl, image_descriptor="test_files/python_logo.png", width=Mm(20), height=Mm(10))
完整代码如下:
from docxtpl import DocxTemplate, InlineImagefrom docx.shared import Mmimport plotly.graph_objects as gofrom io import BytesIOdef generatePieChart(title: str, labels: list, values: list, colors: list): """ 生成饼图 https://juejin.cn/post/6911701157647745031#heading-3 https://juejin.cn/post/6950460207860449317#heading-5 :param title: 饼图标题 :param labels: 饼图标签 :param values: 饼图数据 :param colors: 饼图每块的颜色 :return: """ # 基础饼图 fig = go.Figure(data=[go.Pie( labels=labels, values=values, hole=.4, # 中心环大小 insidetextorientation="horizontal" )]) # 更新颜色 fig.update_traces( textposition="inside", # 文本显示位置 hoverinfo="label+percent", # 悬停信息 textinfo="label+percent", # 饼图中显示的信息 textfont_size=15, marker=dict(colors=colors) ) # 更新标题 fig.update_layout( title={ # 设置整个标题的名称和位置 "text": title, "y": 0.96, # y轴数值 "x": 0.5, # x轴数值 "xanchor": "center", # x、y轴相对位置 "yanchor": "top" } ) image_io = BytesIO() fig.write_image(image_io, format="png") return image_iodef generateBarChart(title: str, x: list, y: list): """ 生成柱状图 https://cloud.tencent.com/developer/article/1817208 https://blog.csdn.net/qq_25443541/article/details/115999537 https://blog.csdn.net/weixin_45826022/article/details/122912484 :param title: 标题 :param x: 柱状图标签 :param y: 柱状图数据 :return: """ # x轴长度最为18 b = x x = [] for i in b: if len(i) >= 18: x.append(f"{i[:15]}...") else: x.append(i) # 基础柱状图 fig = go.Figure(data=[go.Bar( x=x, y=y, text=y, textposition="outside", marker=dict(color=["#3498DB"] * len(y)), width=0.3 )]) # 更新标题 fig.update_layout( title={ # 设置整个标题的名称和位置 "text": title, "y": 0.96, # y轴数值 "x": 0.5, # x轴数值 "xanchor": "center", # x、y轴相对位置 "yanchor": "top" }, xaxis_tickangle=-45, # 倾斜45度 plot_bgcolor="rgba(0,0,0,0)" # 背景透明 ) fig.update_xaxes( showgrid=False ) fig.update_yaxes( zeroline=True, zerolinecolor="#17202A", zerolinewidth=1, showgrid=True, gridcolor="#17202A", showline=True ) image_io = BytesIO() fig.write_image(image_io, format="png") return image_iodoc = DocxTemplate("template.docx")context = { "饼图": InlineImage(doc, image_descriptor=generatePieChart( title="漏洞数量", labels=["严重", "高危", "中危", "低危"], values=[1, 1, 1, 0], colors=["#8B0000", "red", "orange", "aqua"] ), width=Mm(130)), "柱状图": InlineImage(doc, image_descriptor=generateBarChart( title="漏洞类型", x=["测试漏洞名1", "测试漏洞名2", "测试漏洞名3"], y=[1, 1, 1] ), width=Mm(130)), "漏洞简报": [ { "漏洞名": "测试漏洞名1", "漏洞等级": "高危" }, { "漏洞名": "测试漏洞名2", "漏洞等级": "严重" }, { "漏洞名": "测试漏洞名2", "漏洞等级": "中危" } ], "漏洞详情": [ { "漏洞名": "测试漏洞名1", "漏洞地址": "http://blog.gm7.org/", "漏洞等级": "高危", "漏洞危害": "危害XXX", "复现过程": "先xxx,再xxx,最后xxx", "修复建议": "更新到最新版本即可" }, { "漏洞名": "测试漏洞名2", "漏洞地址": "http://bblog.gm7.org/", "漏洞等级": "严重", "漏洞危害": "危害XXX", "复现过程": "先xxx,再xxx,最后xxx", "修复建议": "更新到最新版本即可" }, { "漏洞名": "测试漏洞名3", "漏洞地址": "http://cblog.gm7.org/", "漏洞等级": "中危", "漏洞危害": "危害XXX", "复现过程": "先xxx,再xxx,最后xxx", "修复建议": "更新到最新版本即可" } ]}doc.render(context)doc.save("generated_doc.docx")
结果如下:
result
- END -
关键词:
推荐阅读
世界最贵房车有哪些 福特F550房车怎么样?
世界最贵房车有哪些1 凯迪拉克凯雷德ESV XXXL超级加长房车如果你是那种需要一架空中喷气式飞机和一艘水上游艇的24 × 7大型忙碌者 【详细】
DART小行星任务已开始 有6次自我毁灭航天器介绍
DART小行星任务已开始斯科特·博尔顿曾与两艘飞船合作,这两艘飞船以确保陆地微生物永远无法在太阳系外站稳脚跟的名义自我毁灭。冒着最恶劣 【详细】
十大日系车排名 日系车有怎样的优缺点?
十大日系车排名雷克萨斯UX雷克萨斯UX,官方宣称为紧凑型SUV,但实际上它只是一款小型SUV。UX和C-HR都采用TNGA架构,因此具有很好的可操作性 【详细】
非晶硅薄膜电池的起源 非晶硅薄膜电池优点有哪些?
非晶硅薄膜电池的起源非晶硅薄膜太阳能电池由Carlson和Wronski于20世纪70年代中期成功开发,80年代生产达到高潮,约占全球太阳能电池总量的 【详细】
苹果官网回收旧手机 苹果手机回收注意事项
苹果官网回收旧手机现在很多地方都能回收手机,再生资源回收利用是可以的。苹果是一家非常强大的公司,苹果的手机在国内用户中非常受欢迎。 【详细】
相关新闻
- 快速生成定制化的Word文档:Python实践指南
- 当前速看:用了5年的华为电池快不行了,建议去售后换一块吗?
- “意念回微信”成真了!将在天津这场大会上展示_全球时讯
- 一不小心踩坑里面了,红米note12 Turbo居然不及K40? 环球聚看点
- 关睿怡(关睿怡怎么考到哥伦比亚大学的)_当前头条
- 环球快消息!世茂能源: 公司在定期报告中披露对应期末时点的股东人数信息,请您关注公司定期报告的相关信息
- 星际穿越之男人太多了怎么办 星际之夏娃
- 关键时刻能救命!iPhone新功能在澳上线,没信号也能拨打000求救
- 重点聚焦!关于地震的这些说法不要信!
- 哲库之殇与中国芯片之路
- 速看:TCP/IP 基础知识
- 无论你有多忙,保持健康,永远都是最长远的课题!
- 京东CEO徐雷宣布退休,我终于看懂了28岁从字节跳动离开的郭宇 热讯
- 【天天聚看点】someonelikeyou歌词(someonelikeyou歌词)
- 天天报道:华信新材股东户数减少65户,户均持股19.68万元
- 今日快讯:西安519旅游日景区活动汇总
- 每日快看:黄金和铁都由一样的质子中子和电子组成,为什么价值差别那么大?
- 高科技发展的速度,远比我们想象中快的多,机器人做老婆?...
- 为什么科技越发展,生活越便利,我们反而越累?-环球热议
- 硅胶娃娃对人类社会的影响-快讯