使用 pyautogui 進行跨平臺的 GUI 自動化操作

王雨澤發表於2020-05-14

有個朋友最近問我有沒有推薦 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 和 常見問答 檢視今後的發展路徑。

 

相關文章