一、前言
对系统压测后,需要编写汇总报告。LoadRunner场景生成的Analysis报告,要截图保存部分图片。
 每次几个功能,每个功能几个并发场景,每个场景有4张左右图片。太多重复性工作了,费时费力。
思考:怎么使用程序自动化截图
 查资料:
 pynput、pygetwindow和pyautogui是Python中用于鼠标和键盘控制的三个不同的库。
 pynput库:提供了控制键盘和鼠标的功能。它可以监听和控制键盘的按键事件,以及移动鼠标和执行鼠标点击操作。它的特点是灵活性和控制选项更多,可以实现对键盘和鼠标的高级操作。
 pygetwindow库:提供了管理和控制窗口的功能。它可以获取当前打开的窗口列表,并提供对窗口的操控和属性获取。它的特点是可以通过窗口的标题等属性来查找和操作指定的窗口。
 pyautogui库:是一个自动化测试工具,用于模拟鼠标、键盘和屏幕的操作。它可以控制鼠标的移动、点击和拖放,模拟键盘按键和组合键,并可以对屏幕截图、识别图像等。它的特点是简单易用,适合于自动化任务和GUI测试。
 最终选择了pyautogui,满足点击、截图等需求。
二、学习使用pyautogui库
查询pyautogui库方面的文章:
 https://blog.csdn.net/hfy1237/article/details/127960423
 https://blog.csdn.net/m0_57236802/article/details/129197537
坐标的距离通过像素计算,如果你的屏幕分辨率是1920 x 1080,右下角的像素将是1919, 1079(因为坐标从0开始,而不是1)。
| 函数名 | 功能 | |
|---|---|---|
| 基本 | pyautogui.size() | 返回包含分辨率的元组 | 
| pyautogui.PAUSE | 每个函数的停顿时间,默认0.1s | |
| pyautogui.FAILSAFE | 是否开启防故障功能,默认True | |
| 键盘 | pyautogui.press('键盘字符') | 按下并松开指定按键 | 
| pyautogui.keyDown('键盘字符') | 按下指定按键 | |
| pyautogui.keyUp('键盘字符') | 松开指定按键 | |
| pyautogui.hotkey('键盘字符1', '键盘字符2') | 按下多个指定键 | |
| 鼠标 | pyautogui.position() | 返回当前鼠标当前位置的元组 | 
| pyautogui.moveTo(x,y,duration=1) | 按绝对位置移动鼠标并设置移动时间 | |
| pyautogui.moveRel(x_rel,y_rel,duration=4) | 按相对位置移动鼠标并设置移动时间 | |
| pyautogui.dragTo(x, y, duration=1) | 按绝对位置拖动鼠标并设置移动时间 | |
| pyautogui.dragRel(x_rel, y_rel, duration=4) | 按相对位置拖动鼠标并设置移动时间 | |
| pyautogui.click(x, y) | 鼠标点击指定位置,默认左键 | |
| pyautogui.click(x, y, button='left') | 鼠标单击左键 | |
| pyautogui.click(x, y, button='right') | 鼠标单击右键 | |
| pyautogui.click(x, y, button='middle') | 鼠标单击中间,即滚轮 | |
| pyautogui.doubleClick(10,10) | 鼠标左键双击指定位置 | |
| pyautogui.rightClick(10,10) | 鼠标右键双击指定位置 | |
| pyautogui.middleClick(10,10) | 鼠标中键双击指定位置 | |
| pyautogui.scroll(10) | 鼠标滚轮向上滚动10个单位 | 
press(), keyDowm(),keyUp(),hotKey()支持的有效字符串列表如下:
| 类别 | |
|---|---|
| 字母 | 'a', 'b', 'c', 'd', 'e','f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' | 
| 数字 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' | 
| 符号 | '\t', '\n', '\r', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', , ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~', | 
| F键 | 'f1', 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f2', 'f20', 'f21', 'f22', 'f23', 'f24', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', | 
| 数字键盘 | 'num0', 'num1', 'num2', 'num3', 'num4', 'num5', 'num6', 'num7', 'num8', 'num9', | 
| 其他 | 'accept', 'add', 'alt', 'altleft', 'altright', 'apps', 'backspace', 'browserback', 'browserfavorites', 'browserforward', 'browserhome', 'browserrefresh', 'browsersearch', 'browserstop', 'capslock', 'clear', 'convert', 'ctrl', 'ctrlleft', 'ctrlright', 'decimal', 'del', 'delete', 'divide', 'down', 'end', 'enter', 'esc', 'escape', 'execute', 'final', 'fn', 'hanguel', 'hangul', 'hanja', 'help', 'home', 'insert', 'junja', 'kana', 'kanji', 'launchapp1', 'launchapp2', 'launchmail', 'launchmediaselect', 'left', 'modechange', 'multiply', 'nexttrack', 'nonconvert', , 'numlock', 'pagedown', 'pageup', 'pause', 'pgdn', 'pgup', 'playpause', 'prevtrack', 'print', 'printscreen', 'prntscrn', 'prtsc', 'prtscr', 'return', 'right', 'scrolllock', 'select', 'separator', 'shift', 'shiftleft', 'shiftright', 'sleep', 'space', 'stop', 'subtract', 'tab', 'up', 'volumedown', 'volumemute', 'volumeup', 'win', 'winleft', 'winright', 'yen', 'command', 'option', 'optionleft', 'optionright' | 
三、实现
需求:一个文件夹内有很多Analysis报告,需要打开每一个报告,对summary report、Hits per Second、Average Transaction Response Time、Transactions per Second等页面进行截图保存。
 思路:
 1、获取文件夹内Analysis报告的路径
 2、打开Analysis软件
 3、打开指定报告
 4、截图、保存
 5、重复3、4过程
 6、关闭软件
 实现:
#!/usr/bin/env python 
# -*- coding:utf-8 -*-
import pyautogui
import pyperclip    #复制粘贴 文本复制到剪贴板
import subprocess   #管理子进程
import time
import os
import sys
import re
from PIL import Image
'''
功能:输入路径,扫描路径下2级目录中.lra文件,打开文件进行指定页面截图操作,截图保存在\image中。
设置:max_depth=2设置扫描目录深度,报告要默认有summary report、Hits per Second、Average Transaction Response Time页面,
    没有Transactions per Second页面可以新增。
    页面按钮位置与显示器分辨率有关,在cut()中调整。待匹配图片必须使用pyautogui.screenshot截取,才能匹配到。
'''
# pyautogui.screenshot('sa.png', region=(490,630,760,30)) #截取图标left,top,width,height
# sys.exit()
class lr_cut():
    def __init__(self,folder_path):
        '''
        获取报告路径、名称
        '''
        self.folder_path=folder_path                        # 设置报告文件夹路径
        max_depth=2                                         # 设置遍历文件深度
        self.file_paths=[]                                  # 全部报告路径
        self.file_names=[]                                  # 全部报告名称
        self.file_name=''                                   # 当前报告名称
        self.image_number=0                                 # 已截图报告数量
        for root, dirs, files in os.walk(folder_path, topdown=True):    # 遍历文件夹及其子文件夹中的.lra文件
            depth=root[len(folder_path):].count(os.sep)
            if depth > max_depth:                           # 深度超过限制,不继续递归
                del dirs[:]
            for file in files:
                if file.endswith('.lra'):                   # 条件筛选.lra
                    file_path=os.path.join(root, file)
                    self.file_paths.append(file_path)
        self.count=len(self.file_paths)                     # 统计报告数量
        if self.count == 0:
            print('扫描完成----------没有发现.lra格式的Analysis文件')
            sys.exit()                                      # 没有发现报告,程序退出
        else:
            print(f'扫描完成----------发现{self.count}个Analysis文件')
            pattern=r'[^\\]+(?=\.lra$)'                     # 提取路径中报告名称
            for file_path in self.file_paths:
                match=re.search(pattern, file_path)
                file_name=match.group()
                self.file_names.append(file_name)
    def number_one(self):
        '''
        打开软件,窗口最大化,截图
        '''
        # 打开LoadRunner软件(两种方式)
        # pyautogui.press('win')                            #[1]win搜索Analysis
        # pyautogui.typewrite('Analysis', 0.1)
        # pyautogui.press('enter')
        # pyautogui.press('enter')
        subprocess.Popen(['start', '', self.file_paths[0]], shell=True)  # [2]确保文件关联的程序能够正确打开.lra文件
        time.sleep(9)                                       # 等待LoadRunner启动
        self.file_name=self.file_names[0]                   # 文件名称
        screen_width, screen_height=pyautogui.size()        # 获取屏幕尺寸
        move_distance_x=screen_width // 2
        move_distance_y=screen_height // 2
        pyautogui.click(move_distance_x, move_distance_y)   # 确保文件打开窗口获得焦点
        pyautogui.hotkey('win', 'up')                       # 最大化窗口
        # pyautogui.hotkey('alt', 'space')
        # pyautogui.press('x')
        time.sleep(1)
        self.cut()
    def number_two(self,number):
        '''
        第二次打开文件(软件内打开文件),截图
        '''
        pyautogui.hotkey('ctrl', 'o')
        pyperclip.copy(self.file_paths[number])         # 将路径复制到剪贴板
        time.sleep(1)
        pyautogui.hotkey('ctrl', 'v')                   # 粘贴路径       绕过无法输入中文路径的问题
        pyautogui.press('enter')
        time.sleep(3)
        self.file_name=self.file_names[number]
        self.cut()
    def cut(self):
        '''
        对文件截图,保存在\image中。
        截图命名:报告名称-截图页面.png
        summary report界面匹配事务行数,调整截图高度
        tps截图时,没有tps则添加
        '''
        pyautogui.click(115, 150)  # 点击summary report 截图
        time.sleep(1)
        button_1=pyautogui.locateCenterOnScreen('sa.png', grayscale=True)   #匹配事务行数
        x, y=button_1
        y-=640
        k=351 + y
        name=f'image\\{self.file_name}-summary.png'
        pyautogui.screenshot(name, region=(488, 225, 762, k))       # 截图    每行高度20
        self.resize_screenshot(name)
        pyautogui.click(110, 200)  # 点击Hits per Second 截图
        time.sleep(1)
        name=f'image\\{self.file_name}-Hits.png'
        pyautogui.screenshot(name, region=(480, 100, 1412, 521))    # 截图
        self.resize_screenshot(name)
        k=521 + y
        pyautogui.click(165, 246)  # 点击Average Transaction Response Time 截图
        time.sleep(1)
        name=f'image\\{self.file_name}-Average.png'
        pyautogui.screenshot(name, region=(480, 100, 1412, k))      # 截图
        self.resize_screenshot(name)
        # tps截图,没有tps则添加
        button_position=pyautogui.locateCenterOnScreen('Transactions per Second.png', grayscale=True)  # 定位按钮图片的中心位置
        if button_position == None:
            pyautogui.hotkey('ctrl', 'a')       #添加tps图片
            time.sleep(1)
            button_position2=pyautogui.locateCenterOnScreen('Transactions.png', grayscale=True)
            pyautogui.doubleClick(button_position2)
            time.sleep(1)
            button_position=pyautogui.locateCenterOnScreen('Transactions per Second2.png')
            pyautogui.doubleClick(button_position)
            time.sleep(1)
            pyautogui.hotkey('alt', 'f4')
        pyautogui.click(button_position)
        time.sleep(1)
        name=f'image\\{self.file_name}-tps.png'
        pyautogui.screenshot(name, region=(480, 100, 1412, k))  # 截图
        self.resize_screenshot(name)
        #保存报告
        pyautogui.hotkey('ctrl', 's')
        time.sleep(1)
        self.image_number+=1            #截图报告数统计
    def resize_screenshot(self,name):
        '''
        调整图片大小
        '''
        screenshot=Image.open(name)        # 打开截图
        new_width=696                      # 缩小后的大小
        new_height=348
        resized_screenshot=screenshot.resize((new_width, new_height))       # 缩小截图
        resized_screenshot.save(name)      # 保存缩小后的截图
    def over(self):
        '''
        关闭软件,使用taskkill命令,避免出错后f4关闭其它软件
        '''
        # try:
        #     pyautogui.hotkey('alt', 'f4')
        # except Exception as e:
        #     print(f"pyautogui关闭失败,taskkill强制关闭")
        # finally:
        subprocess.run(["taskkill", "/im", "AnalysisUI.exe", "/f"])  # 使用taskkill命令终止指定的程序。/im参数指定终止程序名称,/f参数强制关闭程序
        print(f'应截报告{self.count}个,已截取报告{self.image_number}个')
    def main(self):
        '''
        1、打开软件,进行第一次截图
        2、在已打开软件内,循环打开文件、截图
        3、关闭软件
        '''
        try:
            self.number_one()
            if self.count > 1:                  # 报告数量>1,循环截图
                for i in range(1, self.count):
                    self.number_two(i)
            else:
                print('报告小于两个,已结束')
        except Exception as e:
            print(f"{self.file_name}--------截取中断:{e.__class__.__name__}")
        finally:
            self.over()
if __name__ == "__main__":
    folder_path = r'C:\Users\feng\Desktop'
    my_instance = lr_cut(folder_path)
    my_instance.main()
    #将鼠标移动到左上角将引发一个 pyautogui.FailSafeException 从而中断程序
效果:
 所有报告截图,图片存放在\image中。
 鼠标移动到左上角,程序中断。
 

 踩坑:
 开始编写代码移动鼠标,运行鼠标没有反应,百度后是权限问题。要管理员身份运行pycharm。
pyautogui.locateCenterOnScreen一直匹配不到按钮截图。百度后发现同样问题,解决方法:不能使用微信等截图工具,要使用pyautogui.screenshot(‘sa.png’, region=(490,630,760,30)),使用pyautogui自带的截图语句,好像是像素点不匹配。
所以要用上面代码的话,要自己根据屏幕分辨率设置点击坐标,重新使用pyautogui.screenshot截取按钮图片。
 链接:https://pan.baidu.com/s/1YDy-x9U8sRL0tiza9SNMLA?pwd=a9d6
 提取码:a9d6



















