用GUI自动控制键盘和鼠标
了解用于编辑电子表格,下载文件和启动程序的各种Python模块是有用的,但有时候没有任何需要使用的应用程序模块。在计算机上自动执行任务的终极工具是您编写的直接控制键盘和鼠标的程序。这些程序可以通过向他们发送虚拟按键和鼠标点击来控制其他应用程序,justpython-就好像您坐在您的计算机上并自行与应用程序进行交互一样。这种技术被称为图形用户界面自动化,简称为GUI自动化。通过GUI自动化,您的程序可以做任何坐在电脑上的人类用户都可以做的事情,除了在键盘上洒咖啡。
将GUI自动化视为编程机器人手臂。您可以编程机器人手臂在键盘上键入并移动鼠标。此技术对于涉及大量无意识点击或填写表单的任务特别有用。
该pyautogui
模块具有模拟鼠标移动,按钮点击和滚动鼠标滚轮的功能。本章仅介绍PyAutoGUI功能的一个子集; 你可以在http://pyautogui.readthedocs.org/找到完整的文档。
安装pyautogui模块
该pyautogui
模块可以发送虚拟按键和鼠标点击到Windows,OS X和Linux。根据您使用的操作系统,在安装PyAutoGUI之前,您可能需要安装一些其他模块(称为依赖项)。
在Windows上,没有其他模块可以安装。
在OS X上,运行
sudo pip3 install pyobjc-framework-Quartz
,sudo pip3 install pyobjc-core
然后sudo pip3 install pyobjc
。在Linux上运行
sudo pip3 install python3-xlib
,sudo apt-get install scrot
,sudo apt-get install python3-tk
,和sudo apt-get install python3-dev
。(Scrot是PyAutoGUI使用的截图程序。)
安装这些依赖项后,运行pip install pyautogui
(或pip3
在OS X和Linux上)以安装PyAutoGUI。
附录A具有关于安装第三方模块的完整信息。要测试PyAutoGUI是否已正确安装,请import pyautogui
从交互式shell 运行并检查是否有错误消息。
保持正轨
在您进入GUI自动化之前,您应该知道如何避免可能出现的问题。Python可以移动鼠标并以令人难以置信的速度输入按键。事实上,其他程序的速度可能会太快。此外,如果出现问题,但您的程序不断移动鼠标,则很难说出程序在做什么或如何从问题中恢复。就像迪士尼魔法师的魔法扫帚一样,然后用水填充 - 然后过度填充 - 米奇的浴缸,即使它完全按照您的指示操作,您的程序仍可能失去控制。如果鼠标单独移动,停止程序可能会很困难,从而阻止您单击IDLE窗口关闭它。幸运的是,有几种方法可以防止或恢复GUI自动化问题。
通过注销关闭所有内容
也许停止失控GUI自动化程序的最简单方法是注销,这将关闭所有正在运行的程序。在Windows和Linux上,注销热键是CTRL - ALT - DEL。在OS X上,它是- SHIFT - OPTION -Q。通过注销,您将失去所有未保存的工作,但至少您不必等待电脑完全重新启动。
暂停和失败保险箱
您可以让脚本在每次函数调用后等待,如果出现错误,您可以通过一个简短的窗口来控制鼠标和键盘。为此,请将该pyautogui.PAUSE
变量设置为您希望暂停的秒数。例如,设置之后pyautogui.PAUSE = 1.5
,每个PyAutoGUI函数调用在执行其操作后都会等待一个半秒。非PyAutoGUI指令不会有这个暂停。
PyAutoGUI还具有故障安全功能。将鼠标光标移动到屏幕的左上角将导致PyAutoGUI引发pyautogui.FailSafeException
异常。您的程序可以使用try
和except
语句来处理这个异常,或让异常崩溃您的程序。无论哪种方式,如果您尽可能快地将鼠标尽可能快地移动,则故障安全功能将停止程序。您可以通过设置禁用此功能pyautogui.FAILSAFE = False
。在交互式shell中输入以下内容:
>>> import pyautogui >>> pyautogui.PAUSE = 1 >>> pyautogui.FAILSAFE = True
在这里,我们导入pyautogui
并设置pyautogui.PAUSE
到1
每个函数调用之后一秒钟的停顿。我们设置pyautogui.FAILSAFE
为True
启用故障安全功能。
控制鼠标移动
在本节中,您将学习如何使用PyAutoGUI移动鼠标并跟踪其在屏幕上的位置,但首先需要了解PyAutoGUI如何与坐标一起工作。
PyAutoGUI的鼠标功能使用x坐标和y坐标。图18-1显示了电脑屏幕的坐标系; 它与第17章讨论的图像坐标系相似。的起源,其中X和ÿ均为零,是在屏幕的左上角。x坐标增加到右边,y坐标增加。所有的坐标都是正整数。没有负面坐标。
你的分辨率是你的屏幕宽度和高度有多少像素。如果屏幕分辨率设置为1920×1080,则左上角的坐标为(0,0),右下角的坐标为(1919,1079)。
该pyautogui.size()
函数以像素为单位返回屏幕宽度和高度的两个整数元组。在交互式shell中输入以下内容:
>>> import pyautogui >>> pyautogui.size() (1920,1080) >>> width,height = pyautogui.size()
pyautogui.size()
(1920, 1080)
在具有1920×1080分辨率的计算机上返回; 取决于您的屏幕分辨率,您的返回值可能会有所不同。您可以从pyautogui.size()
变量中存储宽度和高度width
,height
以便在程序中提高可读性。
移动鼠标
现在您已了解屏幕坐标,让我们移动鼠标。该pyautogui.moveTo()
功能会立即将鼠标光标移动到屏幕上的指定位置。x坐标和y坐标的整数值分别构成函数的第一个和第二个参数。可选的duration
integer或float关键字参数指定将鼠标移动到目标所需的秒数。如果您将其忽略,则默认0
为瞬时移动。(duration
PyAutoGUI函数中的所有关键字参数都是可选的。)在交互式shell中输入以下内容:
>>> import pyautogui >>> for i in range(10): pyautogui.moveTo(100,100,duration = 0.25) pyautogui.moveTo(200,100,duration = 0.25) pyautogui.moveTo(200,200,duration = 0.25) pyautogui.moveTo(100,200,持续时间= 0.25)
本示例在总共提供了十次的四个坐标中以正方形模式顺时针移动鼠标光标。每次移动都需要四分之一秒,正如duration=0.25
关键字参数所指定的那样。如果您没有向任何pyautogui.moveTo()
呼叫传递第三个参数,则鼠标光标将立即从点到点传送。
该pyautogui.moveRel()
函数相对于当前位置移动鼠标光标。下面的示例将鼠标移动到相同的方形图案中,只不过它在代码开始运行时从鼠标碰巧在屏幕上的任何地方开始。
>>> import pyautogui >>> for i in range(10): pyautogui.moveRel(100,0,duration = 0.25) pyautogui.moveRel(0,100,duration = 0.25) pyautogui.moveRel(-100,0,duration = 0.25) pyautogui.moveRel(0,-100,持续时间= 0.25)
pyautogui.moveRel()
还有三个参数:水平向右移动多少像素,向下垂直移动多少个像素,以及(可选)多长时间完成移动。第一个或第二个参数的负整数将导致鼠标分别向左或向上移动。
获取鼠标位置
您可以通过调用该pyautogui.position()
函数来确定鼠标的当前位置,该函数将在函数调用时返回鼠标光标的x和y位置的元组。在交互式shell中输入以下内容,在每次调用后移动鼠标:
>>> pyautogui.position() (311,622) >>> pyautogui.position() (377,481) >>> pyautogui.position() (1536,637)
当然,您的返回值会因鼠标光标的位置而异。
项目:“鼠标现在在哪里?”
能够确定鼠标位置是设置GUI自动化脚本的重要部分。但是通过查看屏幕来确定像素的精确坐标几乎是不可能的。在您移动鼠标光标时,有一个程序可以不断显示鼠标光标的x和y坐标,这将非常方便。
在高层次上,这是你的程序应该做的事情:
显示鼠标光标的当前x和y坐标。
鼠标在屏幕上移动时更新这些坐标。
这意味着您的代码需要执行以下操作:
调用
position()
函数来获取当前坐标。通过
\b
在屏幕上打印退格字符来擦除以前打印的坐标。处理
KeyboardInterrupt
异常,以便用户可以按CTRL -C退出。
打开一个新的文件编辑器窗口并将其保存为mouseNow.py。
第1步:导入模块
用以下方法启动您的程序:
#!python3 #mouseNow.py - 显示鼠标光标的当前位置。 进口pyautogui 打印('按Ctrl-C退出'。) #TODO:获取并打印鼠标坐标。
程序的开始导入pyautogui
模块,并向用户打印一条提醒,他们必须按CTRL -C退出。
第2步:设置退出代码和无限循环
您可以使用无限while
循环来不断打印当前的鼠标坐标mouse.position()
。至于退出程序的代码,您需要捕获KeyboardInterrupt
异常,每当用户按下CTRL -C 时引发异常。如果你不处理这个异常,它会向用户显示一个丑陋的回溯和错误信息。将以下内容添加到您的程序中:
#!python3 #mouseNow.py - 显示鼠标光标的当前位置。 进口pyautogui 打印('按Ctrl-C退出'。) 尝试: while True: #TODO:获取并打印鼠标坐标。 ❶除了一个KeyboardInterrupt: ❷ 打印( '\ nDone')
要处理该异常,请将无限while
循环包含在try
语句中。当用户按下CTRL -C时,程序执行将移至except
子句❶并将Done.
以新行❷打印。
第3步:获取并打印鼠标坐标
while
循环内的代码应该获得当前的鼠标坐标,将它们格式化为好看并打印出来。将以下代码添加到while
循环的内部:
#!python3 #mouseNow.py - 显示鼠标光标的当前位置。 进口pyautogui 打印('按Ctrl-C退出'。) - 剪切 - #获取并打印鼠标坐标。 x,y = pyautogui.position() positionStr ='X:'+ str(x).rjust(4)+'Y:'+ str(y).rjust(4) - snip -
使用多重分配技巧,将x
和y
变量给出了从元组返回两个整数的值pyautogui.position()
。通过传递x
和y
对str()
功能,你可以得到整数坐标的字符串形式。该rjust()
字符串的方法将右对齐他们,让他们占用的空间相同的量,坐标是否有一个,两个,三个或四个数字。将右对齐的字符串坐标与标签连接起来'X: '
,可以' Y: '
为我们提供格式良好的字符串,该字符串将存储在中positionStr
。
在程序结束时,添加以下代码:
#!python3 #mouseNow.py - 显示鼠标光标的当前位置。 - snip - print(positionStr,end ='') ❶print ('\ b'* len(positionStr),end ='',flush = True)
这实际上打印positionStr
到屏幕上。的end=''
关键字参数来print()
阻止默认换行符被添加到印刷线的端部。可以擦除已经打印到屏幕上的文本 - 但仅限于最新的文本行。一旦你打印一个换行符,你就无法擦除它之前的任何东西。
要清除文字,请打印\b
退格转义字符。该特殊字符会擦除屏幕上当前行末尾的字符。❶中的行使用字符串复制来生成一个字符串,其\b
字符数与存储在positionStr
其中的字符串的长度一样多,这会擦除positionStr
上次打印的字符串。
由于技术原因超出了本书的范围,请务必传递flush=True
给print()
打印\b
退格字符的调用。否则,屏幕可能不会根据需要更新文本。
由于while
循环如此快速重复,用户实际上不会注意到您正在删除并重新打印屏幕上的整个号码。例如,如果x坐标是563,并且鼠标向右移动一个像素,则看起来只有563中的3变为4。
当你运行程序时,只会打印两行。他们应该看起来像这样:
按下Ctrl-C以退出。 X:290 Y:424
第一行显示按CTRL -C退出的指令。随着鼠标在屏幕上的移动,鼠标坐标的第二行会发生变化。使用这个程序,你将能够找出你的GUI自动化脚本的鼠标坐标。
控制鼠标交互
既然您知道如何移动鼠标并找出它在屏幕上的位置,就可以开始点击,拖动和滚动了。
点击鼠标
要发送虚拟鼠标点击到您的计算机,请调用该pyautogui.click()
方法。默认情况下,该点击使用鼠标左键并在鼠标光标当前所在的位置进行。如果您希望它发生在鼠标当前位置以外的某个位置,您可以将点击的x坐标和y坐标作为可选的第一个和第二个参数传递。
如果要指定要使用的鼠标按键,包括button
关键字参数,用的值'left'
,'middle'
或'right'
。例如,pyautogui.click(100, 150, button='left')
将在坐标(100,150)处单击鼠标左键,同时pyautogui.click(200, 250, button='right')
将在(200,250)处右键单击。
在交互式shell中输入以下内容:
>>> import pyautogui >>> pyautogui.click(10,5)
您应该看到鼠标指针移动到屏幕的左上角附近并单击一次。完整的“单击”被定义为按下鼠标按钮,然后释放它而不移动光标。您也可以通过调用来执行点击pyautogui.mouseDown()
,只按下鼠标按钮,并且pyautogui.mouseUp()
只释放按钮。这些函数具有与其相同的参数click()
,实际上,click()
函数只是围绕这两个函数调用的便捷包装。
作为进一步的方便,pyautogui.doubleClick()
功能将执行两次点击用鼠标左键,而pyautogui.rightClick()
和pyautogui.middleClick()
功能将与右和中间的鼠标按钮执行的点击,分别。
拖动鼠标
拖动意味着在按住其中一个鼠标按钮的同时移动鼠标。例如,您可以通过拖动文件夹图标在文件夹之间移动文件,也可以在日历应用程序中移动约会。
PyAutoGUI提供pyautogui.dragTo()
并pyautogui.dragRel()
起到将鼠标光标拖动到一个新的位置或相对于当前一个的位置。为参数dragTo()
和dragRel()
是相同的moveTo()
和moveRel()
:x坐标/水平移动,y坐标/垂直运动,以及时的可选的持续时间。(当鼠标移动太快时,OS X不能正确拖动,因此duration
建议传递关键字参数。)
要尝试这些功能,请打开一个图形绘制应用程序,例如Windows上的Paint,OS X上的Paintbrush或Linux上的GNU Paint。(如果您没有绘图应用程序,则可以使用http://sumopaint.com/上的在线应用程序。)我将使用PyAutoGUI绘制这些应用程序。
将鼠标光标放在绘图应用程序的画布上并选择“铅笔”或“画笔”工具,将以下内容输入到新的文件编辑器窗口中,并将其保存为spiralDraw.py:
进口pyautogui,时间 ❶time.sleep(5) ❷pyautogui.click()#点击放置绘图程序 距离= 200 距离> 0时: ❸pyautogui.dragRel(距离,0,持续时间= 0.2)#向右移动 距离=距离 - 5 ❺pyautogui.dragRel(0,distance,duration = 0.2)#向下移动 ❻pyautogui.dragRel(-distance,0,duration = 0.2)#向左移动 距离=距离 - 5 pyautogui.dragRel(0,-distance,duration = 0.2)#向上移动
当你运行这个程序时,会有五秒钟的延迟❶让你将鼠标光标移到绘图程序的窗口上,并选择铅笔或画笔工具。然后,spiralDraw.py将控制鼠标并单击以将绘图程序放在焦点上。当窗口有一个活动的闪烁光标时,窗口处于焦点状态,并且您进行的操作(如本例中拖动鼠标)将影响该窗口。一旦绘图程序处于焦点状态,spiralDraw.py将绘制一个方形螺旋图案,如图18-2所示。
的distance
变量开始于200
,所以在第一次迭代while
循环中,第一dragRel()
呼叫拖动光标200个像素的权利,以0.2秒❸。distance
然后减小到195❹,第二次dragRel()
调用将光标向下拖动195个像素。第三次dragRel()
调用水平拖动光标-195(向左195),distance
减少到190,最后一次dragRel()
调用将光标向上拖动190像素。在每次迭代中,鼠标被向右,向下,向左和向上拖动,并且distance
比前一次迭代时略小。通过循环此代码,您可以移动鼠标光标以绘制方形螺旋。
你可以手工绘制这个螺旋形(或者说,用鼠标),但是你必须慢慢地做到这么精确。PyAutoGUI可以在几秒钟内完成!
注意
您可以使用 模块的绘图功能让您的代码绘制图像pillow
- 请参阅第17章了解更多信息。但使用GUI自动化可以让您利用图形程序可以提供的高级绘图工具,例如渐变,不同的画笔或填充桶。
滚动鼠标
最终的PyAutoGUI鼠标函数是scroll()
,你传递一个整数参数来表示你想向上或向下滚动鼠标的数量。每个操作系统和应用程序的单元大小都不相同,因此您必须尝试查看它在特定情况下滚动的距离。滚动发生在鼠标光标的当前位置。传递一个正整数向上滚动,并传递一个负整数向下滚动。当鼠标光标位于IDLE窗口上时,在IDLE的交互式shell中运行以下代码:
>>> pyautogui.scroll(200)
你会看到IDLE简单地向上滚动 - 然后再往下走。发生向下滚动是因为IDLE在执行指令后自动向下滚动到底部。改为输入此代码:
>>> import pyperclip >>> numbers ='' >>> for i in range(200): numbers = numbers + str(i)+'\ n' >>> pyperclip.copy(数字)
这导入pyperclip
并设置一个空字符串,numbers
。然后代码循环200个数字,并将每个数字numbers
与一个换行符一起添加。之后pyperclip.copy(numbers)
,剪贴板将加载200行数字。打开一个新的文件编辑器窗口并将文本粘贴到其中。这会给你一个很大的文本窗口来尝试滚动。在交互式shell中输入以下代码:
>>> import time,pyautogui >>> time.sleep (5); pyautogui.scroll(100)
在第二行中,输入两个用分号分隔的命令,它告诉Python运行命令,就好像它们在单独的行上一样。唯一的区别是交互式shell不会提示您在两条指令之间输入。这个例子很重要,因为我们希望呼叫pyautogui.scroll()
在等待后自动发生。(请注意,虽然在一行中放置两个命令在交互式shell中可能很有用,但仍然应该在程序中将每条指令放在单独一行中。)
按Enter键运行代码后,您将有五秒钟时间单击文件编辑器窗口将其置于焦点。一旦暂停结束,pyautogui.scroll()
呼叫将导致文件编辑器窗口在五秒延迟后向上滚动。
使用屏幕
您的GUI自动化程序不必单击和盲目输入。PyAutoGUI具有截屏功能,可以根据屏幕的当前内容创建图像文件。这些函数也可以返回Image
当前屏幕外观的Pillow 对象。如果您在本书中一直在跳过,那么在继续阅读本节之前,您需要阅读第17章并安装该pillow
模块。
在Linux计算机上,scrot
需要安装该程序才能使用PyAutoGUI中的屏幕截图功能。在终端窗口中,运行sudo apt-get install scrot
以安装该程序。如果您在Windows或OS X上,请跳过此步骤并继续该部分。
获取屏幕截图
要在Python中截取屏幕截图,请调用该pyautogui.screenshot()
函数。在交互式shell中输入以下内容:
>>> import pyautogui >>> im = pyautogui.screenshot()
该im
变量将包含Image
屏幕截图的对象。您现在可以像调用其他任何对象一样Image
,在im
变量中调用对象的方法Image
。在交互式shell中输入以下内容:
>>> im.getpixel((0,0)) (176,176,175) >>> im.getpixel((50,200)) (130,135,144)
传递getpixel()
坐标元组,如(0,0)或(50,200),它会告诉你图像中坐标的像素颜色。来自的返回值getpixel()
是三个整数的RGB元组,用于像素中红色,绿色和蓝色的量。(alpha没有第四个值,因为截图图像是完全不透明的。)这就是您的程序如何“看到”屏幕上的内容。
分析屏幕截图
假设你的GUI自动化程序的其中一个步骤是点击一个灰色按钮。在调用该click()
方法之前,您可以截取屏幕截图并查看脚本即将点击的像素。如果它不像灰色按钮那样灰色,那么你的程序知道某些东西是错误的。也许窗口意外移动,或者弹出对话框阻止了按钮。在这一点上,不是继续 - 而是可能通过点击错误的东西而造成破坏 - 你的程序可以“看到”它没有点击正确的事物并停止自己。
如果屏幕上给定x坐标和y坐标的像素与给定颜色相匹配,则PyAutoGUI的pixelMatchesColor()
函数将返回True
。第一个和第二个参数是x坐标和y坐标的整数,第三个参数是屏幕像素必须匹配的RGB颜色的三个整数元组。在交互式shell中输入以下内容:
>>> import pyautogui >>> im = pyautogui.screenshot() >>> im.getpixel((50,200)) (130,135,144)p >>> pyautogui.pixelMatchesColor(50,200,(130,135,144)) 真正 >>> pyautogui.pixelMatchesColor(50,200,(255,135,144)) False
在截取屏幕并使用getpixel()
获取特定坐标pixel处像素颜色的RGB元组后,将相同坐标和RGB元组传递给pixelMatchesColor()
❷,该元组应返回True
。然后更改RGB元组中的值并pixelMatchesColor()
再次调用相同的坐标❸。这应该返回false
。只要您的GUI自动化程序即将调用,此方法可用于调用click()
。请注意,给定坐标的颜色必须完全匹配。如果它甚至略有不同 - 例如,(255, 255, 254)
而不是(255, 255, 255)
- 然后pixelMatchesColor()
将返回False
。
项目:扩展mouseNow程序
您可以扩展本章前面的mouseNow.py项目,这样不仅可以给出鼠标光标当前位置的x坐标和y坐标,还可以给出光标下像素的RGB颜色。修改mouseNow.py的while
循环内部代码,如下所示:
#!python3 #mouseNow.py - 显示鼠标光标的当前位置。 - 剪裁 - positionStr ='X:'+ str(x).rjust(4)+'Y:'+ str(y).rjust(4) pixelColor = pyautogui.screenshot()。getpixel((x,y)) positionStr + ='RGB:('+ str(pixelColor [0])。rjust(3) positionStr + =','+ str(pixelColor [1] ).rjust(3) positionStr + =','+ str(pixelColor [2])。rjust(3)+')' print(positionStr,end ='') - 剪裁 -
现在,当您运行mouseNow.py时,输出将包含鼠标光标下像素的RGB颜色值。
按下Ctrl-C以退出。 X:406 Y:17 RGB:(161,50,50)
这些信息与pixelMatchesColor()
功能一起使您可以轻松地将像素颜色检查添加到GUI自动化脚本中。
图像识别
但是如果您事先不知道PyAutoGUI应该点击哪里?您可以使用图像识别。给PyAutoGUI一个你想要点击的图像,并让它找出坐标。
例如,如果以前拍摄截图以捕获submit.png中的提交按钮的图像,该locateOnScreen()
函数将返回找到该图像的坐标。要了解locateOnScreen()
工作原理,请尝试截取屏幕上的一个小区域的屏幕截图; 然后保存图像并在交互式shell中输入以下内容,替换'submit. png'
为屏幕截图的文件名:
>>> import pyautogui >>> pyautogui.locateOnScreen('submit.png') (643,745,70,29)
locateOnScreen()
返回的四个整数元组具有左边缘的x坐标,上边缘的y坐标,宽度和发现图像的第一个位置的高度。如果您使用自己的屏幕截图在计算机上尝试此操作,则返回值将与此处显示的值不同。
如果图像无法在屏幕上找到,locateOnScreen()
将返回None
。请注意,屏幕上的图像必须完美匹配所提供的图像才能被识别。如果图像甚至是一个像素关闭,locateOnScreen()
将返回None
。
如果图像可以在屏幕上的多个位置找到,locateAllOnScreen()
将返回一个Generator
对象,该对象可以传递list()
给返回四元组元组列表。在屏幕上找到图像的每个位置将会有一个四整数元组。通过输入以下内容(并用'submit.png'
您自己的图像文件名替换)继续交互式shell示例:
>>> list(pyautogui.locateAllOnScreen('submit.png')) [ (643,745,70,29),(1007,801,70,29)]
每个四元组元组代表屏幕上的一个区域。如果您的图像仅在一个区域中找到,则使用list()
并locateAllOnScreen()
仅返回包含一个元组的列表。
在找到图像的屏幕上的区域中有四元组元组后,您可以通过将元组传递给center()
函数来返回该区域中心的x和y坐标,从而单击该区域的中心。在交互式shell中输入以下内容,用您自己的文件名,四元组元组和坐标对替换参数:
>>> pyautogui.locateOnScreen('submit.png') (643,745,70,29) >>> pyautogui.center((643,745,70,29)) (678,759) >>> pyautogui.click((678,759))
一旦有了中心坐标center()
,传递坐标就click()
应该点击屏幕上与您传递的图像相匹配的区域中心locateOnScreen()
。
控制键盘
PyAutoGUI还具有将虚拟按键发送到您的计算机的功能,使您可以填写表单或将文本输入到应用程序中。
从键盘发送字符串
该pyautogui.typewrite()
功能将虚拟按键发送到计算机。这些按键的功能取决于窗口和文本字段的重点。您可能需要先将鼠标单击到所需的文本字段以确保其具有焦点。
作为一个简单的例子,我们使用Python来自动输入单词Hello world!进入文件编辑器窗口。首先,打开一个新的文件编辑器窗口并将其放置在屏幕的左上角,这样PyAutoGUI将在正确的位置点击以将其聚焦。接下来,在交互式shell中输入以下内容:
>>> pyautogui.click(100,100); pyautogui.typewrite('Hello world!')
请注意,如何将两条命令放在同一行上,并用分号分隔,这会使交互式shell不会提示您在运行两条指令之间进行输入。这可以防止您意外地将一个新窗口放在焦点click()
和typewrite()
调用之间,这会弄乱该示例。
Python将首先发送一个虚拟鼠标点击到坐标(100,100),这应该单击文件编辑器窗口并将其放在焦点上。该typewrite()
呼叫将发送的文字世界,你好!到窗口,使其看起来像图18-3。你现在有可以为你输入的代码!
默认情况下,该typewrite()
函数将立即键入完整的字符串。但是,您可以传递可选的第二个参数以在每个字符之间添加短暂停顿。第二个参数是要暂停的秒数的整数或浮点值。例如,pyautogui.typewrite('Hello world!', 0.25)
在输入H之后等待四分之一秒,在e之后等四分之一秒。这种渐进的打字机效果可能对于速度较慢的应用程序非常有用,因为这些应用程序无法快速处理键击以跟上PyAutoGUI。
对于A或!等字符 ,PyAutoGUI也会自动模拟按住SHIFT键。
重要名称
并非所有的键都可以用单个文本字符来表示。例如,如何将SHIFT或左箭头键表示为单个字符?在PyAutoGUI,这些键盘键由短字符串值代替表示:'esc'
对于ESC键或'enter'
为ENTER键。
而不是单个字符串参数,可以传递这些键盘键字符串的列表typewrite()
。例如,下面的调用按A键,B键,然后左箭头键两次,最后是X和Y键:
>>> pyautogui.typewrite(['a','b','left','left','X','Y'])
由于按下左箭头键移动键盘光标,这将输出XYab。表18-1列出了可以传递typewrite()
给模拟按键的任意组合的PyAutoGUI键盘键字符串。
您还可以查看pyautogui.KEYBOARD_KEYS
列表以查看PyAutoGUI将接受的所有可能的键盘键字符串。该'shift'
字符串引用左侧的SHIFT键并等同于'shiftleft'
。这同样适用于'ctrl'
,'alt'
和'win'
字符串; 他们都参考左侧的键。
表18-1。 PyKeyboard
属性
键盘键字符串 |
含义 |
---|---|
|
单个字符的键 |
|
该ENTER键 |
|
该ESC键 |
|
左右SHIFT键 |
|
左右ALT键 |
|
左和右CTRL键 |
|
该TAB键 |
|
该退格键和删除键 |
|
该PAGE UP和PAGE DOWN键 |
|
在HOME和END键 |
|
上,下,左,右箭头键 |
|
F1到F12键 |
|
静音,音量减小和音量增大键(某些键盘没有这些键,但您的操作系统仍然能够理解这些模拟按键) |
|
该PAUSE键 |
|
该CAPS LOCK,NUM LOCK和SCROLL LOCK键 |
|
该INS或INSERT键 |
|
该PRTSC或PRINT SCREEN键 |
|
左和右WIN键(在Windows上) |
|
命令 ()键(在OS X) |
按下并释放键盘
很像mouseDown()
和mouseUp()
功能,pyautogui.keyDown()
以及pyautogui.keyUp()
将虚拟按键并释放发送到计算机。他们传递一个键盘键字符串(参见表18-1)以获取它们的参数。为方便起见,PyAutoGUI提供了pyautogui.press()
调用这两个函数来模拟完整按键的功能。
运行下面的代码,它将键入一个美元符号字符(通过按住SHIFT键并按下4来获得):
>>> pyautogui.keyDown('shift'); pyautogui.press( '4'); pyautogui.keyUp( '转向')
该行按下SHIFT,按下(并释放)4,然后释放SHIFT。如果您需要在文本字段中输入字符串,则该typewrite()
函数更适合。但对于采用单键命令的应用程序,该press()
功能是更简单的方法。
热键组合
甲热键或快捷方式是按键的组合,以调用某种应用功能。复制选择的常用快捷键是CTRL -C(在Windows和Linux上)或⌘-C(在OS X上)。用户按住CTRL键,然后按下C键,然后释放C和CTRL键。要使用PyAutoGUI keyDown()
和keyUp()
函数完成此操作,您必须输入以下内容:
pyautogui.keyDown(Ctrl键) pyautogui.keyDown( 'C') pyautogui.keyUp( 'C') pyautogui.keyUp(Ctrl键)
这很复杂。相反,使用该pyautogui.hotkey()
函数需要多个键盘键字符串参数,按顺序按下它们,然后以相反的顺序释放它们。对于CTRL- C示例,代码将如下所示:
pyautogui.hotkey('ctrl','c')
此功能对于较大的热键组合特别有用。在Word中,CTRL - ALT - SHIFT -S热键组合显示样式窗格。而不是做八个不同的函数调用(四个keyDown()
调用和四个keyUp()
调用),您可以调用hotkey('ctrl', 'alt', 'shift', 's')
。
使用屏幕左上角的新IDLE文件编辑器窗口,在交互式shell中输入以下内容(在OS X中,替换'alt'
为'ctrl'
):
>>> 进口pyautogui,时间 >>> DEF commentAfterDelay(): ❶ pyautogui.click(100,100) ❷ pyautogui.typewrite( '在IDLE,Alt键-3注释出的线') time.sleep(2) ❸ pyautogui.hotkey('alt','3') >>> commentAfterDelay()
这个函数定义了一个函数commentAfterDelay()
,当它被调用的时候,它会点击文件编辑器窗口使其进入焦点type,键入In IDLE,Atl-3注释掉一行 ❷,暂停2秒,然后模拟按下ALT -3热键或OS X上的CTRL -3)❸。此键盘快捷键将两个#字符添加到当前行,并将其注释掉。(在IDLE中编写自己的代码时,这是一个很有用的技巧。)
审查PyAutoGUI函数
由于本章涵盖了许多不同的功能,下面是一个快速的总结参考:
moveTo(
x
,
y
)
。移动鼠标光标移动到指定的x
和y
坐标。moveRel(
xOffset
,
yOffset
)
。相对于当前位置移动鼠标光标。dragTo(
x
,
y
)
。按住左键时移动鼠标光标。dragRel(
xOffset
,
yOffset
)
。在按住左键的同时相对于当前位置移动鼠标光标。click(
x
,
y
,
button
)
。模拟点击(默认为左键)。rightClick()
。模拟右键单击。middleClick()
。模拟中间按钮点击。doubleClick()
。模拟双击左键单击。mouseDown(
x
,
y
,
button
)
。模拟按下位置上的给定按钮x
,y
。mouseUp(
x
,
y
,
button
)
。模拟释放给定按钮的位置x
,y
。scroll(
units
)
。模拟滚轮。积极的论据卷起来; 一个负面的观点向下滚动。typewrite(
message
)
。键入给定消息字符串中的字符。typewrite([
key1
,
key2
,
key3
])
。键入给定的键盘键字符串。press(
key
)
。按下给定的键盘键字符串。keyDown(
key
)
。模拟按下给定的键盘按键。keyUp(
key
)
。模拟释放给定的键盘键。hotkey([
key1
,
key2
,
key3
])
。模拟按顺序按下给定的键盘键串,然后按相反的顺序释放它们。screenshot()
。作为Image
对象返回截图。(有关对象的信息,请参阅第17章Image
。)
项目:自动填表
在所有无聊的任务中,填写表格是最可怕的杂事。现在,在最后一章的项目中,你会杀死它。假设电子表格中包含大量数据,并且必须将其重新输入到其他应用程序的表单界面中,而没有实习生可以为你做。虽然有些应用程序具有导入功能,可以让您上传包含这些信息的电子表格,但有时似乎没有别的方法,无意中点击并打字几个小时。这本书你已经走到了这一步; 你知道当然有另一种方法。
此项目的表单是Google文档格式,您可以在http://autbor.com/form找到。它看起来像图18-4。
在高层次上,这是你的程序应该做的事情:
单击表单的第一个文本字段。
浏览表单,在每个字段中输入信息。
点击提交按钮。
用下一组数据重复该过程。
这意味着您的代码需要执行以下操作:
打电话
pyautogui.click()
点击表格并提交按钮。打电话
pyautogui.typewrite()
给字段输入文字。处理
KeyboardInterrupt
异常,以便用户可以按CTRL -C退出。
打开一个新的文件编辑器窗口并将其保存为formFiller.py。
第1步:找出步骤
在编写代码之前,您需要确定填写表单一次的确切键击和鼠标单击。Project中的mouseNow.py脚本:“现在鼠标在哪里?”可以帮助您找出特定的鼠标坐标。您只需要知道第一个文本字段的坐标。点击第一个字段后,您可以按Tab键将焦点移至下一个字段。这将使您不必为每个字段找出点击的x和y坐标。
以下是将数据输入表单的步骤:
点击名称字段。(在使浏览器窗口最大化之后,使用mouseNow.py来确定坐标。在OS X上,您可能需要单击两次:一次将浏览器放在焦点上,然后再次单击“名称”字段。
输入一个名称,然后按Tab键。
输入最大的恐惧,然后按Tab键。
按向下箭头键的正确次数来选择向导电源:魔杖一次,护身符两次,水晶球三次,金钱四次。然后按Tab键。(请注意,在OS X上,每次选项都需要再按一次向下箭头键,对于某些浏览器,您可能还需要按ENTER键。)
按右箭头键选择Robocop问题的答案。按下一次为2,两次3,三次4,或四次5; 或者只需按空格键选择1(默认突出显示)。然后按Tab键。
键入一个额外的评论,然后按Tab键。
按ENTER键“点击”提交按钮。
提交表单后,浏览器会将您带到一个页面,您需要点击链接才能返回到表单页面。
请注意,如果稍后再次运行此程序,则可能必须更新鼠标单击坐标,因为浏览器窗口可能已更改位置。要解决这个问题,在查找第一个表单域的坐标之前,一定要确保浏览器窗口已经最大化。此外,不同操作系统上的不同浏览器可能与此处给出的步骤略有不同,因此请在运行程序之前检查这些按键组合是否适用于您的计算机。
第2步:设置坐标
在浏览器中加载您下载的示例窗体(图18-4)并最大化您的浏览器窗口。打开一个新的终端或命令行窗口来运行mouseNow.py脚本,然后将鼠标悬停在名称字段上找出其x和y坐标。这些数字将被分配给nameField
您的程序中的变量。此外,找出蓝色提交按钮的x和y坐标以及RGB元组值。这些值将分别分配给submitButton
和submitButtonColor
变量。
接下来,为表单填写一些虚拟数据,然后点击提交。您需要查看下一页的外观,以便您可以使用mouseNow.py查找在此新页面上提交另一个响应链接的坐标。
使源代码如下所示,确保将您所测试的坐标替换为斜体中的所有值:
#!python3 #formFiller.py - 自动填写表单。 进口pyautogui,时间 #将这些设置为您计算机的正确坐标。 名称字段=(648,319) 提交按钮=(651,817) submitButtonColor =(75,141,249) submitAnotherLink =(760,224) #TODO:给用户一个杀死脚本的机会。 #TODO:等待表单页面加载完毕。 #TODO:填写姓名字段。 #TODO:填写最伟大的恐惧领域。 #TODO:填写向导权力来源字段。 #TODO:填写Robocop字段。 #TODO:填写额外评论字段。 #TODO:点击提交。 #TODO:等到表单页面加载完毕。 #TODO:点击提交另一个回复链接。
现在您需要实际想要输入此表单的数据。在现实世界中,这些数据可能来自电子表格,纯文本文件或网站,并且需要额外的代码才能加载到程序中。但是对于这个项目,您只需将所有这些数据硬编码到一个变量中。将以下内容添加到您的程序中:
#!python3 #formFiller.py - 自动填写表单。 - 剪裁 - 服务于公众的信任。维护法律。'},] - 剪裁 -
该formData
列表包含四个不同名称的字典。每个字典都有文本字段的名称作为键和响应作为值。设置的最后一步是设置PyAutoGUI的PAUSE
变量在每次函数调用后等待半秒。在formData
赋值语句之后将以下内容添加到您的程序中:
pyautogui.PAUSE = 0.5
第3步:开始键入数据
一个for
循环将迭代formData
列表中的每个字典,将字典中的值传递给将在文本字段中虚拟键入的PyAutoGUI函数。
将以下代码添加到您的程序中:
#!python3 #formFiller.py - 自动填写表单。 - 剪裁 - 对于formData中的人员: #给用户一个杀死脚本的机会。 print('>>> 5 SECOND PAUSE让用户按CTRL-C <<<') ❶time.sleep (5) #等到表单页面加载完毕。 ❷ 同时不pyautogui.pixelMatchesColor(提交按钮[0],提交按钮[1], submitButtonColor): time.sleep(0.5) - 剪裁 -
作为一项小型安全功能,该脚本有五秒暂停❶,让用户有机会按CTRL -C(或将鼠标光标移动到屏幕的左上角以引发FailSafeException
异常)以关闭程序以防万一它出乎意料。然后程序会等待提交按钮的颜色可见,让程序知道表单页面已经加载。请记住,你已经明白了坐标和颜色信息,并将其存储在变量submitButton
和submitButtonColor
变量中。要使用pixelMatchesColor()
,请传递坐标submitButton[0]
和submitButton[1]
颜色submitButtonColor
。
等待“提交”按钮的颜色可见之后,添加以下代码:
#!python3 #formFiller.py - 自动填写表单。 - 剪裁 - ❶ 打印( '输入%s,信息...' %(人[ '姓名'])) ❷ pyautogui.click(名称字段[0],名称字段[1]) #填写姓名字段。 ❸ pyautogui.typewrite(人[ '名称'] + '\ T') #填写最伟大的恐惧(s)领域。 ❹ pyautogui.typewrite(人[ '恐惧'] + '\ T') - 剪裁 -
我们添加一个偶尔的print()
调用来在终端窗口中显示程序的状态,让用户知道发生了什么事情。
由于程序知道表单已加载,因此可以调用click()
以单击名称字段❷并typewrite()
在person['name']
❸中输入字符串。该'\t'
字符被添加到传递给的字符串的末尾typewrite()
以模拟按TAB,这将键盘焦点移动到下一个字段,最大的恐惧(s)。另一个呼叫typewrite()
将在person['fear']
此字段中输入字符串,然后选择表单中的下一个字段。
第4步:处理选择列表和单选按钮
“向导强大”问题的下拉菜单和Robocop字段的单选按钮比文本字段更难处理。要用鼠标点击这些选项,您必须找出每个可能选项的x和y坐标。使用键盘上的箭头键更容易进行选择。
将以下内容添加到您的程序中:
#!python3 #formFiller.py - 自动填写表单。 - 剪裁 - #填写向导权力来源字段。 ❶ 如果人[ '源'] == '棒': ❷ pyautogui.typewrite([ '向下', '\吨']) 的elif人[ '源'] == '护身符': pyautogui.typewrite(['向下'''''')) elif person ['source'] =='水晶球': pyautogui.typewrite(['down','down','down','\ t']) elif person ['source'] =='money': pyautogui.typewrite(['down','down','down','down','\ t']) #填写Robocop字段。 ❸ 如果人[ '机械战警'] == 1: ❹ pyautogui.typewrite([” ' '\吨']) 的elif人[ '机械战警'] == 2: pyautogui.typewrite([ '右',' \吨']) elif person ['robocop'] == 3: pyautogui.typewrite(['right','right','\ t']) elif person ['robocop'] == 4: pyautogui.typewrite([''右','右','右','\ t']) elif person ['robocop'] == 5: pyautogui.typewrite(['right','right','right','right',' \吨']) - 剪裁 -
一旦下拉菜单具有焦点(请记住,在填写最大恐惧字段后,您编写了模拟按Tab的代码),按向下箭头键将移至选择列表中的下一个项目。根据中的值person['source']
,您的程序应该在切换到下一个字段之前发送多个向下箭头按键。如果该值'source'
在该用户的字典关键是'wand'
❶,我们模拟按下箭头键一次(选择棒),然后按TAB ❷。如果'source'
键的值是'amulet'
,我们模拟两次按向下箭头键并按TAB,等等其他可能的答案。
Robocop问题的单选按钮可以用右箭头键选择 - 或者,如果您想选择第一个选项❸,只需按空格键❹即可。
第5步:提交表单并等待
您可以typewrite()
通过person['comments']
作为参数传递来填充附加注释字段。您可以键入附加内容'\t'
将键盘焦点移至下一个字段或提交按钮。一旦提交按钮处于焦点状态,调用pyautogui.press('enter')
将模拟按ENTER键并提交表单。提交表单后,您的程序将等待五秒钟以加载下一页。
一旦新页面加载完成,它将会有一个提交另一个响应链接,它将引导浏览器到一个新的空表单页面。您submitAnotherLink
在步骤2 中将此链接的坐标作为元组存储,因此请传递这些坐标pyautogui.click()
以单击此链接。
随着新表单准备就绪,脚本的外部for
循环可以继续进行下一次迭代,并将下一个人的信息输入到表单中。
通过添加以下代码来完成您的程序:
#!python3 #formFiller.py - 自动填写表单。 - 剪裁 - #填写额外的评论字段。 pyautogui.typewrite(person ['comments'] +'\ t') #点击提交。 pyautogui.press( '输入') #等到表单页面加载完毕。 打印('点击提交') time.sleep(5) #点击提交另一个回复链接。 pyautogui.click(submitAnotherLink [0],submitAnotherLink [1])
主for
循环完成后,程序将插入每个人的信息。在这个例子中,只有四个人进入。但是如果你有4000人,那么编写一个程序来做到这一点会节省你很多时间和打字!
概要
使用该pyautogui
模块进行GUI自动化可让您通过控制鼠标和键盘与计算机上的应用程序进行交互。虽然这种方法足够灵活,可以做任何人类用户可以做的事情,但缺点是这些程序对于他们点击或键入的内容相当盲目。在编写GUI自动化程序时,尽量确保如果给出错误的指令,它们将很快崩溃。崩溃令人讨厌,但它比继续错误的程序要好得多。
您可以在屏幕上移动鼠标光标并使用PyAutoGUI模拟鼠标点击,击键和键盘快捷键。该pyautogui
模块还可以检查屏幕上的颜色,这可以为您的GUI自动化程序提供足够的屏幕内容的想法,以了解它是否偏离了轨道。你甚至可以给PyAutoGUI一个屏幕截图,让它找出你想要点击的区域的坐标。
您可以将所有这些PyAutoGUI功能组合起来,以便在计算机上自动执行任何无意识的重复性任务。事实上,它可以彻底催眠观察鼠标光标自动移动并看到文本自动出现在屏幕上。为什么不花时间坐下来看看你的节目为你做了所有的工作?看到你的聪明如何将你从无聊的东西中拯救出来,有一定的满足感。
实践问题
问: |
1.如何触发PyAutoGUI的失败安全来停止程序? |
问: |
2.什么函数返回当前 |
问: |
3.什么函数返回鼠标光标当前位置的坐标? |
问: |
4. |
问: |
5.什么功能可以用来拖动鼠标? |
问: |
6.什么函数调用会输出字符 |
问: |
7.你怎样才能做特殊按键的按键,如键盘的左箭头键? |
问: |
8.如何将屏幕的当前内容保存到名为screenshot.png的图像文件? |
问: |
9.什么代码会在每次PyAutoGUI函数调用后设置两秒的暂停? |
实践项目
对于练习,编写执行以下操作的程序。
看起来很忙
许多即时消息程序通过在一段时间内检测到鼠标移动不足(例如,十分钟)来确定您是闲置还是远离计算机。也许你想暂时离开办公桌一段时间,但不希望别人看到你的即时通讯状态进入闲置模式。写一个脚本,每10秒轻轻推动一下鼠标光标。微调应该足够小,以免在脚本运行时碰巧需要使用计算机时妨碍它。
Instant Messenger Bot
Google Talk,Skype,Yahoo Messenger,AIM和其他即时消息应用程序通常使用专有协议,这使得其他人难以编写可与这些程序进行交互的Python模块。但即使这些专有协议也无法阻止您编写GUI自动化工具。
Google Talk应用程序有一个搜索栏,可让您在好友列表中输入用户名,并在按ENTER时打开消息窗口。键盘焦点自动移动到新窗口。其他即时消息应用程序有类似的方式来打开新的消息窗口。编写一个程序,该程序会自动发送通知消息给您的朋友列表中的一组人员。您的程序可能需要处理特殊情况,例如朋友处于离线状态,聊天窗口出现在屏幕上的不同坐标处,或确认信箱中断您的消息。您的程序将不得不采取屏幕截图来指导其GUI交互,并采用检测虚拟键击未被发送的方式。
注意
您可能需要设置一些虚假的测试帐户,以便在编写此程序时不会意外地发送给真正的朋友。
玩游戏的Bot教程
有一篇很棒的教程,标题为“如何构建可以玩网络游戏的Python Bot”,可以在http://nostarch.com/automatestuff/找到。本教程介绍了如何使用Python创建一个名为Sushi Go Round的Flash游戏的GUI自动化程序。游戏涉及点击正确的成分按钮来填补顾客的寿司订单。您填写订单的速度越快,没有错误,您获得的积分就越多。对于GUI自动化程序来说,这是一个非常适合的任务 - 并且是一种欺骗得分最高的方法!本教程涵盖了本章涵盖的许多相同主题,还包括PyAutoGUI基本图像识别功能的说明。