一、前言
对系统压测后,需要编写汇总报告。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