当前位置:   article > 正文

自动化报告神器:python-docx批量插入图片,性能测试报告秒成_pandas python-docx 添加多个图片

pandas python-docx 添加多个图片

1、前言

1.1、先说下平时性能测试报告编写。

  在第一次性能测试脚本执行后,确认了有无性能问题,是否达标。未达标则优化,再次测试,重复这个过程。
  最后一次测试后,将测试数据汇总,报送相关负责人,确认后,则开始性能测试报告编写。根据测试场景,打开每一个测试结果,截图粘贴。重复以上工作,一个繁琐且耗时的过程。

1.2、提升报告编写效率:自动化脚本的力量

  之前对 测试结果截图 这一过程进行了优化:通过编写自动化截图工具,实现了一次性将所有测试结果自动截图。减少了重复打开测试结果,重复截图的过程。详见基于PyAutoGUI图片定位的自动化截图工具–完成了

本次目标:使用Python高效操作Word,将所有截图对应插入到性能测试报告中,以减少截图粘贴的时间

  九层之台,始于累土。每个脚本,都要为提效服务。一次解决一个耗时点,逐步打磨完善。

2、学习python-docx

  python-docx 是一个用于处理 .docx 文件(即 Microsoft Word 文档)的 Python 库。它允许开发者读取、修改现有文档,以及创建新的 .docx 文件。python-docx 提供了一种直观的方式来操作 Word 文档中的各种元素,包括文本、表格、图片、页眉、页脚、样式等等。
安装:pip install python-docx

2.1、主要概念

  • Document: 表示整个 Word 文档。
  • Paragraph: 表示文档中的段落,每个段落可以包含多行文本。
  • Run: 段落中具有相同格式的一段文本,如字体、大小、颜色等。
  • Table: 表格,由行和列组成,可以嵌入文档中。
  • Row: 表格中的一行。
  • Cell: 表格中的单元格,可以包含文本、图片或其他元素。
  • Image: 可以插入文档中的图像。
  • Styles: Word 中的样式,用于控制文本和段落的外观。

2.2、基本操作

  1. 创建新文档:
from docx import Document
doc = Document()
  • 1
  • 2
  1. 添加文本:
doc.add_paragraph('Hello world!')
  • 1
  1. 保存文档:
doc.save('hello_world.docx')
  • 1
  1. 读取文档:
doc = Document('existing_document.docx')
for para in doc.paragraphs:
    print(para.text)
  • 1
  • 2
  • 3
  1. 添加图片:
doc.add_picture('image.jpg', width=Inches(1.25))
  • 1
  1. 添加表格:
table = doc.add_table(rows=1, cols=3)
row_cells = table.rows[0].cells
row_cells[0].text = 'Cell 1'
row_cells[1].text = 'Cell 2'
row_cells[2].text = 'Cell 3'
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 设置样式:
style = doc.styles['Normal']
font = style.font
font.name = 'Times New Roman'
font.size = Pt(12)
  • 1
  • 2
  • 3
  • 4
  1. 访问样式:
para.style = doc.styles['Heading 1']
  • 1
  • 使用技巧
    使用 run 来改变段落中不同部分的格式,如加粗、斜体、下划线等。
    利用 table 的属性和方法来控制表格的布局和内容。
    可以利用 python-docx 的样式系统来保持文档风格一致。

3、自动插入图片实现

本次使用python-docx 打开文档,读取段落信息。
  功能:将截图,批量插入到word文档《性能测试报告》中
  输入:.png截图文件夹路径,.docx报告路径,图片重命名替换字符串字典
  输出:已插入图片的报告
  报告要求:需建立与图片对应的,场景、并发与性能指标的标题

3.1、流程设计

在这里插入图片描述

3.2、函数实现

1. rename_files

将工具截图的命名格式,改成与性能测试报告标题匹配的格式。返回图片路径列表。
通过修改字典,将要删除或替换的字符,写成键值对{‘原名称’:‘正确名称’}

# 旧字符串及其替换的新字符串
replacement_dict = {'正式-': '',
                    '-10-606.csv': '',
                    'jp@gc - Response Times Over Time': '事务响应时间',
                    'jp@gc - Transactions per Second': '每秒请求通过数(TPS)',
                    '聚合报告': '测试结果摘要',
                    'jp@gc - Hits per Second': '每秒点击数',
                    '-50-': '-50并发-',
                    '-100-': '-100并发-',
                    '-200-': '-200并发-',
                    '-300-': '-300并发-',
                    '-400-': '-400并发-',
                    '-500-': '-500并发-',
                    '-1000-': '-1000并发-',
                    }

def rename_files(folder_path, replacement_dict):
    """
    重命名文件夹内的所有png文件
    :param folder_path: 图片文件夹路径
    :param replacement_dict: 替换字符串字典
    :return: 重命名后图片路径列表
    """
    image_paths = []  # 存储图片路径的列表
    # 遍历文件夹内的所有文件
    try:
        for filename in os.listdir(folder_path):
            if filename.endswith('.png'):  # 检查文件是否为.png
                new_name = filename
                for key, value in replacement_dict.items():
                    if key in filename:
                        new_name = new_name.replace(key, value)  # 替换字符串
                if new_name != filename:  # 如果文件名发生了变化
                    os.rename(os.path.join(folder_path, filename), os.path.join(folder_path, new_name))
                    # print(f'"{filename}" to "{new_name}"')

                image_paths.append(os.path.join(folder_path, new_name))
    except Exception as e:
        print(f"重命名过程中发生错误: {e}")
    return image_paths
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

实现下图效果,命名:场景描述-并发数-性能指标.png,例如:单位职工参保登记-300-测试结果摘要.png
在这里插入图片描述

2. get_image_info

传入图片路径,分解图片信息,返回:场景描述、并发数、性能指标。

def get_image_info(image_path):
    """
    获取图片信息
    :param image_path: 图片路径
    :return: 图片信息:场景描述、并发数、性能指标
    """
    filename = os.path.basename(image_path)  # 提取文件名
    pattern = r'(.*)-(.*)-(.*)\.png'  # 定义正则表达式模式
    match = re.match(pattern, filename)  # 匹配文件名

    if match:
        scene_description = match.group(1)  # 场景描述
        concurrency = match.group(2)  # 并发数
        metric = match.group(3)  # 性能指标
        return scene_description, concurrency, metric
    else:
        print(f"{image_path}文件名格式不正确,无法解析。")
        return None, None, None
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

3. insert_image

根据图片信息,判断插入位置,插入图片到文档

def insert_image(image_paths, doc, count):
    """
    遍历图片路径列表,根据图片信息,判断插入位置,插入图片到文档
    :param image_paths: 图片路径
    :param doc: 打开的word文档
    :param count: 成功图片数
    :return count: 成功图片数
    """
    for image_path in image_paths:
        scene_description, concurrency, metric = get_image_info(image_path)
        scene_description_flag = False  # 关键词标记,辅助定位图片插入位置
        concurrency_flag = False
        # 遍历文档中的所有段落
        for paragraph in doc.paragraphs[100:]:  # 切片,去除目录等
            p = paragraph.text
            if scene_description in paragraph.text:
                scene_description_flag = True
            elif scene_description_flag and concurrency in paragraph.text:
                concurrency_flag = True
            elif concurrency_flag and metric in paragraph.text:
                run = paragraph.add_run()  # 创建一个新的Run对象并添加到当前段落
                run.add_break()  # 添加一个换行符
                run.add_picture(image_path, width=Inches(5.5))  # 在当前Run中插入图, 设置宽高, height=Inches(3.0)3.0英寸
                # print(f"{image_path}插入成功")
                count += 1
                scene_description_flag = False  # 关键词标记,辅助定位图片插入位置
                concurrency_flag = False
    return count
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

报告的结构如下,有n个功能场景,场景下n个并发,并发下有4个性能指标。
图片经过get_image_info分解出:场景描述、并发数、性能指标,3个信息。
  1.先将“场景描述”进行段落文本遍历,符合 scene_description_flag = True 。
  2.再对“并发数”进行遍历,concurrency_flag = True。
  3.最后找到“性能指标”标题,在他后面插入图片。同时重置标记
这样就可以找到图片对应位置。

在这里插入图片描述

4. add_images_to_report

打开报告,处理图片。对插入结果、耗时等信息,进行统计。

def add_images_to_report(folder_path, report_path, replacement_dict):
    """
    插入所有图片,报告保存。
    :param folder_path: 文件夹路径
    :param report_path: 报告路径
    :param replacement_dict: 替换字符串字典
    :return: None
    """
    count = 0
    start_time = datetime.now()
    image_paths = rename_files(folder_path, replacement_dict)
    try:
        doc = Document(report_path)  # 打开Word文档
        count = insert_image(image_paths, doc, count)  # 插入图片
        if count > 0:
            doc.save(report_path)  # 保存修改后的文档
    except Exception as e:
        print(f"修改文档时发生错误:{e}")
    finally:
        completion_rate = (count / len(image_paths)) * 100 if len(image_paths) > 0 else 0  # 计算完成度
        end_time = datetime.now()
        time_duration = (end_time - start_time).total_seconds()
        print(
            f"文件夹图片【{len(image_paths)}】张,实际插入【{count}】张\n完成度:{completion_rate:.2f}%\n耗时:{time_duration}秒")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

5. 执行

if __name__ == '__main__':
    print("开始插入图片...")
    folder_path = r'C:\Users\1\Downloads\Report diagram'  # 图片文件夹路径
	report_path = r'C:\Users\1\Downloads\Report diagram\性能测试报告.docx'  # 报告路径
    add_images_to_report(folder_path, report_path, replacement_dict)
  • 1
  • 2
  • 3
  • 4
  • 5

4、自动化报告效果

4.1、自动截图

先使用 自动化截图工具 把80张图片截取出来,耗时4分39秒。

请添加图片描述

4.2、批量插入图片

运行脚本,选择截图文件夹。报告是在压测优化中途,找时间编写的模板,建立对应场景标题。

插图耗时2.22秒
在这里插入图片描述

报告插入图片效果如下:
在这里插入图片描述

4.3、总结

  在测试中途,编写性能测试报告模板。结束测试,将压测数据写入性能测试报告。 自动化截图工具 实现了5分钟内截图, python-docx批量插入图片 实现了图片2秒插入。后续只需要填写测试数据与结论等,就可以完成报告。
  编写脚本完成重复性工作,最终塑造了整个流程的高效和流畅。脚本的编写并非一蹴而就,而是需要不断地打磨和完善。我们从最初的单一功能脚本起步,逐步扩展其能力,增加复杂度,希望最终构建出一套能够覆盖性能测试报告编写全过程的自动化工具。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/987797
推荐阅读
相关标签
  

闽ICP备14008679号