网络编程
位置:首页>> 网络编程>> Python编程>> Python快速生成定制化的Word(docx)文档

Python快速生成定制化的Word(docx)文档

作者:初始安全  发布时间:2022-04-27 12:33:06 

标签:Python,定制化,Word,docx

1.1. 前言

众所周知,安服工程师又叫做Word工程师,在打工或者批量SRC的时候,如果产出很多,又需要一个一个的写报告的情况下会非常的折磨人,因此查了一些相关的资料,发现使用python的docxtpl库批量写报告效果很不错,记录一下。

1.2. 介绍

docxtpl 是一个用于生成 Microsoft Word 文档的模板引擎库,它结合了 docx 模块和 Jinja2 模板引擎,使用户能够使用 Microsoft Word 模板文件并在其中填充动态数据。它提供了一种方便的方式来生成个性化的 Word 文档,并支持条件语句、循环语句和变量等控制结构,以满足不同的文档生成需求。

官方GitHub地址:https://github.com/elapouya/python-docx-template

官方文档地址:https://docxtpl.readthedocs.io/en/latest/

简单来说:就是创建一个类似Jinja2语法的模板文档,然后往里面动态填充内容就可以了

安装:

pip3 install docxtpl

1.3. 基础使用

from docxtpl import DocxTemplate
doc = DocxTemplate("test.docx")
context = {'whoami': "d4m1ts"}
doc.render(context)
doc.save("generated_doc.docx")

其中,test.docx内容如下:

Python快速生成定制化的Word(docx)文档

生成后的结果如下:

Python快速生成定制化的Word(docx)文档

1.4. 案例介绍

1.4.1. 需求假设

写一份不考虑美观的漏扫报告,需要有统计结果图和漏洞详情,每个漏洞包括漏洞名、漏洞地址、漏洞等级、漏洞危害、复现过程、修复建议六个部分。

1.4.2. 模板文档准备

编写的模板文档如下,使用到了常见的iffor赋值等,保存为template.docx,后续只需要向里面填充数据即可。

Python快速生成定制化的Word(docx)文档

1.4.3. 数据结构分析

传入数据需要一串json字符串,因此我们根据模板文档梳理好json结构,然后传入即可。

梳理好的数据结构如下:

{
  "饼图": "111",
  "柱状图": "222",
  "漏洞简报": [
    {
      "漏洞名": "测试漏洞名1",
      "漏洞等级": "高危"
    }
  ],
  "漏洞详情": [
    {
      "漏洞名": "测试漏洞名1",
      "漏洞地址": "http://blog.gm7.org/",
      "漏洞等级": "高危",
      "漏洞危害": "危害XXX",
      "复现过程": "先xxx,再xxx,最后xxx",
      "修复建议": "更新到最新版本即可"
    }
  ]
}

编写代码测试一下可行性:

from docxtpl import DocxTemplate
doc = 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")

很好,达到了预期的效果。

Python快速生成定制化的Word(docx)文档

1.4.4. 加入图表

在上面的过程中,内容几乎是没问题了,但是图表还是没有展示出来。生成图表我们使用plotly这个库,并将生成内容写入ByteIO

相关代码如下:

import plotly.graph_objects as go
from io import BytesIO
def 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_io
def 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

1.4.5. 最终结果

要插入图片内容,代码语法如下:

myimage = InlineImage(tpl, image_descriptor='test_files/python_logo.png', width=Mm(20), height=Mm(10))

完整代码如下:

from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm
import plotly.graph_objects as go
from io import BytesIO
def 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_io
def 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
doc = 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")

结果如下:

Python快速生成定制化的Word(docx)文档

来源:https://segmentfault.com/a/1190000043792745

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com