有個朋友最近問我有沒有推薦 GUI 桌面應用自動化的技術,我只能回答他:不好意思,這個真有,他是 pyautogui。主要有三大特征:
- 純純的 python, 源碼一覽無余;
- 跨平台,linux, windows, mac 他都能上;
- 操作簡單,會代碼就能上手。
pyautogui 進行 web 自動化文件上傳不要太簡單。熟悉 web 自動化測試的大佬應該都懂,當采用 js 調用原生控件進行文件上傳的時候,最常用的是使用 pywin32 等系統交互庫。

當看到 pywin32 那丑陋的 api 封裝只能爆粗口。就為了輸入一個文件地址,需要整這么多莫名其妙的代碼(看不懂沒關系,只需要看代碼行數就夠了):

我們來看看使用 pyautogui 多么簡單:
#輸入文件名
pyautogui.write(r'd:\demo.txt')
# 回車
pyautogui.press('enter', presses=2)
pyautogui 不支持中文輸入。但是可以復制剪切板,間接實現中文輸入:
import pyperclip
pyperclip.copy('D:\用戶.html')
time.sleep(2)
pyautogui.hotkey('ctrl', 'v')
pyautogui.press('enter', presses=2)
跨平台的使用和安裝
上面的代碼在 mac ,linux 和 windows 上是通用的,只是在 mac 和 linux 下需要安裝額外的依賴。
windows 安裝不需要其他依賴,直接使用了 python 自帶的 ctypes 模塊:
pip install pyautogui
mac 安裝需要 PyObjC 模塊:
pip3 install pyobjc-core
pip3 install pyobjc
pip3 install pyautogui
linux 需要依賴 python3-Xlib 或者 python-xlib(python2):
pip3 install python3-xlib
pip3 install pyautogui
linux 如果沒有安裝相關 python 庫可能會報錯。 Debian 系發行版(其他發行版自行了解)你可能需要輸入:
sudo apt-get install scrot
sudo apt-get install python3-tk
sudo apt-get install python3-dev
鼠標操作
pyautogui 並不需要去解析各平台的控件結構,他的元素定位都是基於坐標的。所以不論你是通過手工截圖測量,還是通過自動化工具獲取,只要你能拿到坐標,你就能進行元素操作。
獲取坐標
import pyautogui as ui
# 獲取屏幕大小
size = ui.size()
# 獲取現在鼠標位置
p = ui.position()
# 坐標是否超出屏幕范圍
if_on = ui.onScreen(*p)
鼠標移動
ui.moveTo(x/2, y/2, duration=2, tween=easeInCirc)
參數說明:
- x, y 坐標
- duration 持續秒數,默認是瞬間完成
- tween 特效,一般沒什么用。
鼠標拖拽, 移動到指定的坐標
ui.dragTo(500, 500)
百發百中的射箭游戲
import random
import time
import pyautogui as ui
x, y = ui.position()
target = (800, 800)
for i in range(10):
rand_x = random.randint(0, x)
rand_y = random.randint(0, y)
# 隨機生成位置
print(rand_x, rand_y)
ui.moveTo(rand_x, rand_y)
# 移動到目標位置
ui.dragTo(target, duration=0.2)
time.sleep(1)
效果: 
相對移動
ui.move(-500, duration=1)
ui.move(yOffset=-400, duration=1)
ui.move(500, duration=1)
ui.move(yOffset=400, duration=1)
相對移動的小游戲
start = 20
add_point = 10
duration = 0.5
for i in range(10):
if i % 2 == 0:
ui.drag(start, duration=duration)
ui.drag(yOffset=start, duration=duration)
else:
ui.drag(-start, duration=duration)
ui.drag(yOffset=-start, duration=duration)
start += add_point
效果:

點擊操作
ui.click(x=None,
y=None,
clicks=1, # 點擊次數
interval=0.0, # 間隔時間
button='right', # 右鍵
duration=0.0) # 持續時間
通過 click 進一步封裝了 leftClick, rightClick, middleClick, doubleClick, tripleClick
scroll 窗口滾動操作
窗口滾動,但是封裝的滾動感覺比較雞肋,他是以鼠標點擊次數為單位的,所以不知道會滾動到什么位置。
pyautogui.scroll(10) # 向上滾動 10 個 clicks
>>> pyautogui.scroll(-10) # # 向下滾動 10 個 clicks
>>> pyautogui.scroll(10, x=100, y=100) # 移動到位置再滾動
使用 drag 和 dragTo 會更加方便一點,還是以坐標為依據,通過操作鼠標中鍵來實現窗口滾動,比如這個例子是 scroll 和 drag 的對比:
x, y = ui.size()
ui.scroll(-100)
time.sleep(1)
ui.scroll(100)
time.sleep(1)
ui.dragTo(y=y, button='middle') # 滾動到窗口底部
效果:
鍵盤操作
輸入框輸入
# 輸入yuz, 每個字母時間間隔 0.2 s
pyautogui.write("yuz",interval=0.2)
注意:pyautogui 並不支持輸入框自動聚焦,所有輸入之前先要點擊輸入框位置。
按下鍵盤 press
press('enter', presses=1, interval=0.0)
相當於鼠標操作的 click, 可以輸入鍵盤上的按鍵, 比如 shift 鍵,enter 鍵。所有的按鍵可以查看源碼當中的 KEYBOARD_KEYS 或者 KEY_NAMES。
參數:
- presses, 操作按鍵次數
- interval, 每次按鍵的間隔時間
所有按鍵列表:

熱鍵 hotkey
ui.hotkey('ctrl', 'shift', 'esc')
keyUp, keyDown
這是 press 的分解動作,相當於鼠標的 mouseUp 和 mouseDown。上面熱鍵的操作方式可以分解成:
ui.keyDown('ctrl') # 按下 ctrl
ui.keyDown('shift') # 按下 shift
ui.keyDown('esc') # 按下 esc
ui.keyUp('esc') # 釋放 ctrl
ui.keyUp('shift') # 釋放 shift
ui.keyUp('ctrl') # 釋放 esc
圖像識別
坐標定位這種方式為通用性打下了基礎,讓 pyautogui 可以輕松做到跨平台。但是實際操作過程中很難清除的知道某個要操作的控件的確切位置,因為每次打開相同的頁面都有可能是變動的。pyautogui 給出的解決方案非常簡單粗暴,使用圖像識別,返回在屏幕中的坐標位置,在通過坐標進行處理。
locateCenterOnScreen
返回被識別圖像的中心坐標。參數說明:
- 必傳參數,圖片路徑;
- confidence, 識別精度,需要安裝 opencv 才能使用;
- grayscale, 灰度級別,能夠提升識別速度。
locateCenterOnScreen('img/seven.png', confidence=0.7, grayscale=True)
現階段圖像識別的結果並不理想,基於圖像識別的使用還存在以下問題:
-
識別不到指定元素;
-
識別精度不夠;
-
查找速度比較慢
-
需要用到重型的 opencv 庫, 或許可以嘗試換用其他庫。
-
需要提前准備被識別的圖片,如果操作元素多,手動處理素材會懷疑人生。
所以 uiautogui 適合的場景是跨平台的少量原生控件交互,如果要對原生應用控件大量操作,還是換用其他工具比較合適。
基於圖像識別的具體例子:
import time
import pyautogui as ui
time.sleep(3)
seven = ui.locateCenterOnScreen('img/seven.png', confidence=0.7, grayscale=True)
mult = ui.locateCenterOnScreen('img/multipy.png', confidence=0.7, grayscale=True)
two = ui.locateCenterOnScreen('img/two.png', confidence=0.7, grayscale=True)
equal = ui.locateCenterOnScreen('img/equal.png', confidence=0.7, grayscale=True)
ui.click(*seven)
ui.click(*mult)
ui.click(*two)
ui.click(*equal)
效果:
后期可以期待的
pyautogui 現階段最欠缺的是無法獲取窗口。但是可以通過 PyGetWindow 等工具進行集成。你可以通過官網 roadmap 和 常見問答 查看今后的發展路徑。
