自动化测试之桌面自动化(PyAutoGUI)
1、PyAutoGUI介绍
- pyautogui是用来做GUI桌面应用自动化的Python包,功能类似于按键精灵:可以实现控制鼠标、键盘、消息框、截图、定位功能
- 官方文档: https://pyautogui.readthedocs.io/en/latest/
- pyautogui的特点:
- 纯python实现, 源码清晰可见
- 跨平台,支持linux、windows、mac
- 操作简单,会Python就行
- 需要特别注意的是:pyautogui不支持中文输入,但是可以配合pyperclip模块进行复制粘贴
安装:
# Windows安装pyautogui pip install pyautogui -i https://pypi.tuna.tsinghua.edu.cn/simple # mac安装pyautogui pip install pyobjc-core pip install pyobjc pip install pyautogui # Linux安装pyautogui #sudo apt-get install scrot python3-tk python3-dev pip install python3-xlib pip install pyautogui
2、鼠标操作
2.1、屏幕和鼠标的位置
屏幕上的位置由X和Y直角坐标表示。X坐标从左侧的0开始,向右增加。与数学不同,Y坐标从顶部的0开始,向下增加。
+---------------------------+ | | Y increases | | | | 1920 x 1080 screen | | | | V | | | | +---------------------------+ 1919, 1079
- 左上角的像素位于坐标0、0。如果屏幕的分辨率为1920 x 1080,则右下角的像素将为1919、1079(因为坐标始于0,而不是1)。
屏幕分辨率大小由该
size()
函数作为两个整数的元组返回。该position()
函数返回鼠标光标的当前X和Y坐标。在Python交互模式下,运行如下代码:
import os import time import pyautogui print(pyautogui.size()) # 屏幕分辨率 try: while True: x, y = pyautogui.position() # 返回鼠标的坐标 # 打印当前鼠标位置坐标 print(f'鼠标坐标:x={x}, y={y}') time.sleep(1) # 捕获异常 KeyboardInterrupt:用户中断执行(通常是输入^C) except KeyboardInterrupt: print('已退出')
- 要检查XY坐标是否在屏幕上,请将它们(作为两个整数参数或带有两个整数的单个元组/列表参数)传递给
onScreen()
函数,True
如果它们在屏幕边界之内,则返回该函数False
。
>>> pyautogui.onScreen(0, 0) True >>> pyautogui.onScreen(0, -1) False
2.2、鼠标移动
该moveTo()
函数会将鼠标光标移至您传递的X和Y整数坐标。例如:
import pyautogui # 在每次PyAutoGUI调用(具体的操作)后就会有2秒的暂停 pyautogui.PAUSE = 2 pyautogui.moveTo(100, 200) # moves mouse to X of 100, Y of 200. pyautogui.rightClick() # 鼠标原地右键单击 pyautogui.moveTo(800, 800) # moves mouse to X of 800, Y of 800. pyautogui.rightClick() # 鼠标原地右键单击
通常,鼠标光标会立即移动到新坐标。如果您希望鼠标逐渐移动到新位置,请在移动所需的持续时间(以秒为单位)中传递第三个参数。例如:
import pyautogui pyautogui.moveTo(100, 200) # moves mouse to X of 100, Y of 200 pyautogui.rightClick() # 鼠标原地右键单击 pyautogui.moveTo(800, 800, 2) # moves mouse to X of 800, Y of 800 over 2 seconds pyautogui.rightClick() # 鼠标原地右键单击
如果要将鼠标光标相对于其当前位置(相对位置)移动几个像素,请使用该move()
功能。此函数的参数与相似moveTo()
。例如:
import pyautogui # 在每次PyAutoGUI调用(具体的操作)后就会有2秒的暂停 pyautogui.PAUSE = 2 pyautogui.moveTo(140*2, 80*2) # moves mouse to X of 140*2, Y of 80*2. pyautogui.rightClick() # 鼠标原地右键单击 # 从当前位置移动鼠标 pyautogui.move(188*2, 155*2) # move the mouse left 188*2, down 155*2 pixels. pyautogui.rightClick() # 鼠标原地右键单击
2.3、鼠标拖拽
PyAutoGUI dragTo()
和drag()
函数的参数与moveTo()
和move()
函数的参数相似。此外,它们还有一个button
可以设置为'left'
,的关键字'middle'
,并且'right'
在拖动时按住该鼠标键不放。例如:
import pyautogui # 在每次PyAutoGUI调用(具体的操作)后就会有2秒的暂停 pyautogui.PAUSE = 2 # button可以设为 left, middle和right pyautogui.dragTo(35*2, 35*2, button='left') # drag mouse to X of 35*2, Y of 35*2 while holding down left mouse button pyautogui.drag(500, 0, 5) # 按住鼠标左键,用5秒钟把鼠标相对于(35*2, 35*2)往右移动500
2.4、鼠标点击
该click()
功能模拟在鼠标的当前位置单击鼠标左键。“点击”的定义是按下按钮然后将其释放。例如:
pyautogui.click() # click the mouse
要moveTo()
在点击之前合并调用,请为x
and y
关键字参数传递整数:
pyautogui.click(x=100, y=200) # move to 100, 200, then click the left mouse button.
要指定不同的鼠标键点击,传递'left'
,'middle'
或 'right'
为button
关键字参数:
pyautogui.click(button='right') # right-click the mouse
要进行多次点击,请将整数传递给clicks
关键字参数。(可选)您可以将float或integer传递给interval
关键字参数,以指定两次点击之间的暂停时间(以秒为单位)。例如:
pyautogui.click(clicks=2) # double-click the left mouse button pyautogui.click(clicks=2, interval=0.25) # double-click the left mouse button, but with a quarter second pause in between clicks pyautogui.click(button='right', clicks=3, interval=0.25) ## triple-click the right mouse button with a quarter second pause in between clicks
作为便捷的快捷方式,该doubleClick()
功能将双击鼠标左键。它还具有可选x
,y
,interval
,和button
关键字参数。例如:
pyautogui.doubleClick() # perform a left-button double click
import pyautogui # 在每次PyAutoGUI调用(具体的操作)后就会有2秒的暂停 pyautogui.PAUSE = 2 # pyautogui.moveTo(40*2, 130*2) # moves mouse to X of 40*2, Y of 40*2. # pyautogui.doubleClick() # perform a left-button double click # pyautogui.doubleClick(40*2, 130*2) # 等价于上面2步 pyautogui.click(40 * 2, 130 * 2, 2, button='left') # 和上面等价
2.5、mouseDown()、mouseUp()
鼠标单击和拖动包括按下鼠标按钮并向上释放鼠标按钮。如果要单独执行这些操作,请调用mouseDown()
和mouseUp()
函数。它们具有相同的x
,y
和button
。例如:
pyautogui.mouseDown(); pyautogui.mouseUp() # does the same thing as a left-button mouse click pyautogui.mouseDown(button='right') # press the right button down pyautogui.mouseUp(button='right', x=100, y=200) # move the mouse to 100, 200, then release the right button up.
2.6、鼠标滚动
可以通过调用该scroll()
函数并传递整数个“单击”来滚动鼠标滚轮。在不同平台上,“单击”中的滚动量会有所不同。例如:
import pyautogui # 在每次PyAutoGUI调用(具体的操作)后就会有2秒的暂停 pyautogui.PAUSE = 2 pyautogui.click(300 * 2, 100 * 2) # 移动到(300*2, 100*2)位置 pyautogui.scroll(-1000) # 向下滚动1000格 pyautogui.scroll(1000) # 向上滚动1000格
2.7、保护措施
Python移动鼠标、点击键盘非常快,有可以导致其他应用出现问题。在这种情况下,程序可能会失控(即使是按照你的意思执行的),那时就需要中断。如果鼠标还在自动操作,就很难在程序窗口关闭它。
为了能够及时中断,PyAutoGUI提供了一个保护措施。当pyautogui.FAILSAFE = True
时,如果把鼠标光标在屏幕左上角,PyAutoGUI函数就会产生pyautogui.FailSafeException
异常。如果失控了,需要中断PyAutoGUI函数,就把鼠标光标在屏幕左上角。要禁用这个特性,就把FAILSAFE
设置成False
:
import pyautogui # 建议PAUSE和FAILSAFE一起使用 # 在每次PyAutoGUI调用(具体的操作)后就会有2秒的暂停 pyautogui.PAUSE = 2 # 将鼠标移动到左上角将引发pyautogui.FailSafeException,可终止程序,设置False禁用此特性 pyautogui.FAILSAFE = False
2.8、方法、属性汇总
方法或属性 | 作用 |
pyautogui.PAUSE=2 | 操作间隔2秒 |
pyautogui.FAILSAFE = True |
开启故障安全模式 |
pyautogui.position() | 获取当前鼠标坐标,单位为像素 |
pyautogui.size() | 获取当前屏幕分辨率,单位为像素 |
pyautogui.onScreen(x, y) |
判断坐标是否在当前屏幕中,返回值为True和False |
pyautogui.moveTo(x, y, duration) | 将鼠标移动到指定的 x、y 坐标 (屏幕以左上角为原点(0,0),向下y增加,向右x增加),使用duration值设置几秒后移动鼠标到指定的 x、y 坐标 |
pyautogui.move(x, y, duration) | 相对于当前的鼠标位置移动鼠标 |
pyautogui.dragTo(x, y, duration, button) | 默认按下左键,移动鼠标,button可设置为left, middle和right |
pyautogui.drag(x, y, duration, button) | 默认按下左键,相对于当前位置移动鼠标 |
pyautogui.click( x, y, clicks=1,button) | 模拟点击(默认是左键),clicks=1,2,3(单击、双击、三击) |
pyautogui.rightClick() | 模拟右键点击 |
pyautogui.middleClick() | 模拟中键点击 |
pyautogui.leftClick() | 模拟左键点击 |
pyautogui.doubleClick() | 模拟左键双击 |
pyautogui.mouseDown(x, y, button) | 模拟在 x、y 处按下指定鼠标按键 |
pyautogui.mouseUp(x, y, button) | 模拟在 x、y 处释放指定键 |
pyautogui.scroll(units) | 模拟滚动滚轮。正参数表示向上滚动,负参数表示向下滚动。 |
3、键盘操作
3.1、write()
主要键盘功能是write()
。此函数将在所传递的字符串中键入字符。要在按下每个字符键之间添加延迟间隔,请为interval
关键字参数传递一个int或float值。pyautogui不支持中文输入,但是可以配合pyperclip模块进行复制粘贴。
import pyautogui import pyperclip # 在每次PyAutoGUI调用(具体的操作)后就会有1秒的暂停 pyautogui.PAUSE = 1 pyautogui.write('Hello world!') # prints out "Hello world!" instantly pyautogui.write('Hello world!') pyautogui.write('传智播客') # 不支持中文,不显示 # 显示中文的操作 pyperclip.copy('黑马程序员') pyautogui.hotkey('ctrl', 'v') # 按下ctrl+v快捷键 # 建议 鼠标要放在这行注释下方的代码区 再右键运行
3.2、press()、keyDown()、keyUp()
- 要按下这些键,调用
press()
函数,从它传递一个字符串pyautogui.KEYBOARD_KEYS
,例如enter
,esc
,f1
。 - 该
press()
函数实际上只是keyDown()
和keyUp()
函数的包装,它们模拟按下一个键然后释放它。这些功能可以自己调用。 - 要按类似的方式按多个键
write()
,请将字符串列表传递给press()
import pyautogui # 在每次PyAutoGUI调用(具体的操作)后就会有1秒的暂停 pyautogui.PAUSE = 1 pyautogui.press('enter', presses=3) # 按下并松开(轻敲)回车键(共3次) pyautogui.write(['enter', 'enter', 'enter']) # 和上面等价 pyautogui.write('123') pyautogui.press('enter') # 回车 # 输出 $ 或 ¥ 符号的按键 pyautogui.keyDown('shift') # 按下`shift`键 pyautogui.press('4') pyautogui.keyUp('shift') # 松开`shift`键 # 建议 鼠标要放在这行注释下方的代码区 再右键运行
3.3、hotkey()
为了方便快捷地按下热键或键盘快捷键,hotkey()
可以传递几个键字符串,这些字符串将按顺序按下,然后以相反的顺序释放。
pyautogui.hotkey('ctrl', 'shift', 'esc')
# 等效于以下代码:
pyautogui.keyDown('ctrl')
pyautogui.keyDown('shift')
pyautogui.keyDown('esc')
pyautogui.keyUp('esc')
pyautogui.keyUp('shift')
pyautogui.keyUp('ctrl')
3.4、KEYBOARD_KEYS
以下是有效字符串传递给press()
,keyDown()
,keyUp()
,和hotkey()
功能:
['\t', '\n', '\r', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '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', '{', '|', '}', '~', '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', 'f1', 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f2', 'f20', 'f21', 'f22', 'f23', 'f24', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'final', 'fn', 'hanguel', 'hangul', 'hanja', 'help', 'home', 'insert', 'junja', 'kana', 'kanji', 'launchapp1', 'launchapp2', 'launchmail', 'launchmediaselect', 'left', 'modechange', 'multiply', 'nexttrack', 'nonconvert', 'num0', 'num1', 'num2', 'num3', 'num4', 'num5', 'num6', 'num7', 'num8', 'num9', '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']
3.5、方法、属性汇总
方法或属性 | 作用 |
pyautogui.KEYBOARD_KEYS |
可以控制的按键名称 |
pyautogui.write(msg) | 输入字符,不支持中文 |
pyperclip.copy(msg) | 复制内容msg,内容可设置为中文等 |
pyautogui.write([key1,key2]) | 键入给定键字符串,只能是英文 |
pyautogui.press(key) | 按下并释放给定键 |
pyautogui.keyDown(key) | 按住按键 |
pyautogui.keyUp(key) |
松开按键 |
pyautogui.hotkey('ctrl', 'v') | 模拟按顺序按下给定键字符串,然后以相反的顺序释放 |
4、信息框操作
4.1、简介
PyAutoGUI利用PyMsgBox中的消息框功能提供了一种跨平台的纯Python方式来显示JavaScript样式的消息框,所有弹窗都会阻塞程序。
4.2、alert()
pyautogui.alert(text='', title='', button='OK')
显示带有文本和单个“确定”按钮的简单消息框。返回单击的按钮的文本。
4.3、confirm()
pyautogui.confirm(text='', title='', buttons=['OK', 'Cancel'])
显示带有“确定”和“取消”按钮的消息框。可以自定义按钮的数量和文本。返回单击的按钮的文本。
4.4、prompt()
pyautogui.prompt(text='', title='' , default='')
显示带有文本输入以及“确定”和“取消”按钮的消息框。返回输入的文本,如果单击“取消”,则返回“无”。
4.5、password()
pyautogui.password(text='', title='', default='', mask='*')
显示带有文本输入以及“确定”和“取消”按钮的消息框。输入的字符显示为*
。返回输入的文本,如果单击“取消”,则返回“无”。
4.6、消息框方法汇总
方法 | 作用 |
pyautogui.alert() |
简单提示消息框 |
pyautogui.confirm() | 多按钮消息框 |
pyautogui.prompt() | 明文输入消息框 |
pyautogui.password() | 密文输入消息框 |
5、截图定位操作
5.1、简介
- PyAutoGUI可以截取屏幕截图,将其保存到文件中,并在屏幕上定位图像。如果您有一个很小的图像,例如需要单击一个按钮并想在屏幕上找到它的按钮,这很有用。
这些功能由PyScreeze模块提供,该模块随PyAutoGUI一起安装。
屏幕截图功能需要Pillow模块。
- OS X使用操作系统
screencapture
随附的命令。 - Linux使用该
scrot
命令,可以通过运行进行安装:sudo apt-get install scrot
- OS X使用操作系统
5.2、screenshot()
- 调用
screenshot()
将返回一个Image对象。传递文件名字符串将把屏幕截图保存到文件中,并将其作为Image对象返回。 region
如果您不需要整个屏幕的屏幕截图,则还有一个可选的关键字参数。您可以传递区域的左侧,顶部,宽度和高度的四整数元组来捕获。
import pyautogui # 截全屏并设置保存图片的位置和名称 im1 = pyautogui.screenshot('./images/screenshot1.png') print(im1) # 打印图片的属性 # 不截全屏,截取区域图片。截取区域region参数为:左上角XY坐标值、宽度和高度 pyautogui.screenshot('./images/screenshot2.png', region=(0, 0, 300, 400))
5.3、定位功能
5.3.1、locateOnScreen
- PyAutoGUI可以通过图片,在屏幕上定位图像所在的位置。
- 调用
locateOnScreen(图片路径)
函数以获取屏幕图像坐标,返回值为4整数元组:(左,上,宽度,高度),可以传递此元组center()
以获取该区域中心的X和Y坐标。如果没有找到,返回None
import pyautogui # 可以通过图片,在屏幕上定位图像所在的位置 # 找到返回的是一个4边距元组 (top, left, width, height),没有找到返回None # 全屏幕搜素 rect = pyautogui.locateOnScreen('./images/computer.png') print(rect) # Box(left=36, top=222, width=84, height=120) if rect: # rect不为None才往下操作 print(rect[0], rect[1], rect[2], rect[3]) # 36 222 84 120 x, y = pyautogui.center(rect) # 获取rect该区域中心的X和Y坐标 print(x, y)
5.3.2、locateCenterOnScreen
locateCenterOnScreen()
函数结合locateOnScreen()
和center()
import pyautogui # 可以通过图片,在屏幕上定位图像所在的位置,该区域中心的X和Y坐标 point = pyautogui.locateCenterOnScreen('./images/computer.png') print(point) if point: # point不为None才往下操作 x, y = point print(x, y)
5.4、提高定位精度
可选的confidence
关键字参数指定函数在屏幕上定位图像的精度
- 这个参数范围和环境有关,需要在0~1之间调试最佳参数
- 需要安装OpenCV才能使
confidence
关键字起作用:pip install opencv-python
import pyautogui # 可以通过图片,在屏幕上定位图像所在的位置 # 找到返回的是一个4边距元组 (top, left, width, height),没有找到返回None # 全屏幕搜素 rect = pyautogui.locateOnScreen('./images/x3.png', confidence=0.6) print(rect)
5.5、加速定位
- 指定搜索区域
pyautogui.locateOnScreen('./images/computer.png', region=(0, 0, 400, 400))
- (可选)可以传递
grayscale=True
给locate函数以略微加快速度(大约30%-ish)。这会使图像和屏幕截图的颜色降低饱和度,从而加快定位速度。
pyautogui.locateOnScreen('./images/computer.png', grayscale=True)
5.6、方法汇总
方法 | 汇总 |
pyautogui.screenshot() | 截屏 |
pyautogui.locateOnScreen() | 从屏幕寻找图片位置,返回一个4边距坐标 |
pyautogui.locateCenterOnScreen() | 从屏幕寻找图片位置,返回中心点坐标 |
6、案例:自动写字表白
- 自动打开记事本
- 自动写字
如花,今晚看电影如何?今晚刚好敲完代码!!
,每隔0.3秒写一个字 - 自动保存文件
- 自动关闭记事本
参考代码:
import pyautogui import os import multiprocessing import time import pyperclip # 进程处理函数 def start_notepad(): os.system('notepad') # 阻塞,不按关闭,不会往下执行 def write_word(words, t=0.1): for v in words: pyperclip.copy(v) pyautogui.hotkey('ctrl', 'v') time.sleep(t) def main(): # 1. 创建进程 p = multiprocessing.Process(target=start_notepad) # 2. 进程启动 p.start() time.sleep(1) # 2.1 定位软件 point = pyautogui.locateCenterOnScreen('./love_imgs/note2.png', confidence=0.6) print(point) pyautogui.click(point.x, point.y) time.sleep(0.5) # 3. 写字 write_word('如花,今晚看电影如何?今晚刚好敲完代码!!', 0.3) # 4. 保存文件 pyautogui.hotkey('ctrl', 's') time.sleep(1) # 5. 写字,保存文件的文件名 write_word('表白记录.txt', 0.2) # 6. 回车 pyautogui.press('enter') # 7. 按个y确定保存 pyautogui.press('y') time.sleep(1) # 8. 关闭当前的pycharm pyautogui.hotkey('alt', 'f4') time.sleep(1) # 9. 关闭记事本软件 pyautogui.hotkey('alt', 'f4') if __name__ == '__main__': main()