macOS 效率進階,學習如何用 AppleScript 實現自動化
聽Yvesss老師的建議修改了標題,原標題:「快速上手 macOS GUI Scripting: 基於 UI 元素的系統自動化控制」。
GUI Scripting 可以幫助你實現如下圖一樣的效果:打開記賬軟體,並在其中進行複雜繁瑣的自動化錄入操作——幾乎所有點擊操作都在瞬間完成。過程中,我實際進行的操作只有:激活這個腳本、輸入消費金額和消費內容而已。
GIF
在 Money Pro 中錄入一次消費
GUI Scripting 的原理很簡單,就是利用腳本語言模擬滑鼠鍵盤操作,進而控制系統 UI 元素。比如說,點擊窗口中的某個按鈕、在某個文本框里輸入信息、以及獲取窗口內特定區域的文本等等。這些可能單調繁瑣的工作,你都可以用 GUI Scripting 來解放雙手,實現無延遲的自動化。
本文介紹的是 macOS 下的 GUI Scripting,macOS 系統中提供了現成的腳本語言 AppleScript,以及及其輕量化的原生 IDE 「腳本編輯器」,無需任何準備就能輕易上手。下面我就以動圖中控制 Money Pro 為例,向你介紹 GUI Scripting 的基本方法。我相信讀完文章後,你可以完全掌握常見 UI 元素的自動化控制。
擴展閱讀:不僅是 macOS,Windows 下也有 GUI Scripting,在少數派的這篇文章里有具體介紹。
AppleScript 基礎
首先需要介紹幾點 AppleScript 基礎,它們太基本了,實在無法繞過,希望你可以耐心讀完,如果有任何問題也可以在評論中提出,我會一一解答。這裡介紹所有代碼你均可在「腳本編輯器」里測試。
1. 「告訴 xxx 做某事」的俄羅斯套娃結構
AppleScript 的語法非常接近自然語言,想要操控一個應用(application)做某件事,只要直接「告訴」它就好了。
UI 元素層級
然而,如果想要用 訪問某一個 UI 元素,必須按上圖中的層級結構,一層一層按順序進行訪問:System Events 是最外圍的框架 Money Pro(具體某個應用) window 1(該應用的第1個窗口) button 1(窗口中的第1個按鈕)。理解和掌握這種層級關係,是進行 GUI Scripting 非常關鍵的一步。
System Events 是系統應用(application),要「告訴」它做某事,AppleScript 要這麼寫,
所有帶 UI 結構的應用,都是 System Events 下的進程(process),包括 Money Pro。如果我要「告訴」Money Pro 做某事,因為它是套在 System Events 之內的,就要這麼寫
再進一步,我們要控制 Money Pro 的第一個窗口,就是
以此類推,你可以無限 下去,
我們需要控制的 UI 元素一般藏在比較深的層級中,它們的完整描述都很長。拿下圖中的「軟體」菜單項舉例,這個例子將會會貫穿全文。
「軟體」菜單項
圖中被選中的這個「軟體」菜單項的完整描述是「Money Pro 應用中的第一個窗口中的第一個可滾動區域中的第一個表單中的第二列中的第一個 UI 元素中的第一個彈出菜單按鈕的第一個彈出菜單中的菜單項「買買買」的第一個菜單中的「軟體」菜單項」,在 AppleScript 中就是
其實這就是一句十分生硬、表示從屬關係的英文,相比於中文「xxx中的xxx」,英文則是「of」,且關係倒置——子級在先,父級在後。至於我為什麼知道是第 1 個按鈕 button 1 而不是 button 2 或 button 3,這將作為重要內容在下一節詳細說明。
2. 小憩片刻
運行 AppleScript 時,如果你需要暫停片刻,那麼就用
3. 注釋
AppleScript 中凡是雙短線 和井號 後的內容都會被認為是注釋,不會被執行。
4. 模擬鍵盤操作
鍵盤的模擬操作也需在 System Events 內進行。
你可以用 來模擬鍵盤操作鍵入一串字元,
也可以用 來實現單鍵操作,比如利用
來模擬點擊鍵盤上的 Escape 鍵。完整的鍵位代碼你可以在這裡找到。
如何定位 UI 元素,獲取它的完整描述
這一節將重點說明如何去獲取一個 UI 元素。緊接著上文 Money Pro 的例子——關於我????是如何獲得那個「軟體」菜單項的 AppleScript 完整描述。
對於毫無經驗的我們,其策略就是,先獲取整個應用內所有 UI 元素,然後縮小範圍(比如該應用第 x 個窗口),再然後再憑直覺篩選出一些可能是目標元素的語句,逐個試驗它們,最終定位目標 UI 元素。
1. 獲取一個區域內的所有 UI 元素
任何一個 UI 元素,只有在軟體當前的界面中存在,才能被獲取和使用。一個獲取失敗的例子:沒有被呼出的菜單里的內容,是無法被獲取的。
右圖中「軟體」菜單項可以被獲取和操作,而左圖不行
用 AppleScript 獲取某個區域內所有 UI 元素只需兩個單詞 。
例如,利用
你就會得到 Money Pro 這整個應用所有的 UI 元素的完整描述,甚至是頂部菜單欄中的內容。UI 元素之間被逗號隔開。
運行結果中數量多到令人窒息的 UI 元素
如果你需要進一步縮小範圍,比如我不想看菜單欄的內容,那就再套一層2的語句:
你就會得到內容比之前少一些,但同樣很多的 UI 元素。
2. 篩選可能是目標 UI 元素的內容
不同 UI 元素的篩選方法各不相同,似乎沒有捷徑。
如果這個元素有名稱,比如菜單項顯示的文字,那就直接查找這個文字!比如對於那個菜單項「軟體」,如果你搜「軟體」,直接就能定位到。
但並非所有開發者都會好好地給 UI 元素起名字,或者出於設計考慮,會刻意隱去名稱,比如哪些就沒有名字,而是用一個序號來標識 。在這種你搜不了名字的情況下,你還可以用這樣一個經驗性規律——腳本運行結果中的所有 UI 元素是按軟體界面中從上到下,從左到右的順序排列的。所以你可以查找它附近的元素,然後在這個元素前後用肉眼識別。
你還可能遇到不熟悉的 UI 元素類型(比如不確定一個按鈕的類型該是 ,還是 ),你可以利用原生應用「Accessibility Inspector」去審查它,它長這個樣子,Spotlight 一搜就能搜到:
Accessibility Inspector
點擊上面那個「瞄準」按鈕,就能用滑鼠指針查看 99% UI 元素的信息,其中包含了 UI 元素的種類(Type)。
滑鼠指向「2160p 4K」按鈕後的效果
獲取目標 UI 元素的過程看起來,複雜可怕,但只要敢於嘗試,成功那麼一兩次,你就會變得經驗老道了。
定位 UI 元素之後可以做什麼?
1. 如果是按鈕或者菜單項,你可以在 AppleScript 里模擬點擊 它,比如點擊之前那個「軟體」菜單項。
因為我們處在進程 Money Pro 的 中,所以需要注釋掉後面 的部分。
2. 如果是文本輸入框,你可以設置文本框內容。
也可以設置激活該輸入框的游標,
利用這些操作你可以逐個試驗你定位到的元素,以最終確定哪一個是目標元素。由於篇幅限制,本篇文章無法涵蓋所有 UI 元素的可控屬性,需要了解更多請查閱 UI 元素的對應文檔。但對我而言,能夠實現圖標點擊、菜單項點擊,文本框內容輸入就完全足夠了。
讓我們來點擊這個「軟體」菜單項
前文說到,只有顯示出來的 UI 元素才能被獲取和操作,所以要想點擊「軟體」這個菜單項,我必須先讓「軟體」這個菜單項顯示出來,於是我必須選中「買買買」這個菜單項。讓「買買買」菜單項顯出出來,我又必須點擊「類別」按鈕彈出類別菜單。「類別」按鈕又是處在 Money Pro 新建面板中的。所以整個操作流程應該是
打開 Money Pro 主窗口
點擊右上角的 + 號按鈕,彈出新建面板
點擊面板上的「類別」按鈕,彈出類別菜單
選擇「買買買」
再選「軟體」
從第 2 步開始每一步都是一次 UI 元素的操控命令。你必須先獲取 + 號按鈕的 AppleScript 描述,然後用 操作點擊它;再獲取「類別」按鈕的描述,點擊它;再獲取「買買買」菜單項的描述,點擊它,最後獲取「軟體」菜單項的描述,點擊它。
完整的 AppleScript 腳本是
值得一提的小事
如何使用 UI 元素的描述語句,取決於所處層級
你可能已經注意到了,只要處於某個層級內部,對一個 UI 元素進行操作使用的並不是它的完整描述。
還是拿點擊那個「軟體」菜單項為例,我們是這樣寫的:
但你也可以這樣寫:
後者里,我多套了一個 的結構,所以 事件里就不必要把 包括進去了,因為 事件已處於 window 1 的層級內了。
我這裡提供一個最喪病的寫法,可能可以促進理解,但實際編寫時不具備參考價值
兩次 click 事件之間的延遲問題
正常情況下你無法快速點擊兩次菜單項——兩次 事件之間會被強行插入一個 5 秒左右的延遲。這是 macOS 的保護機制,為了應用的 UI 反饋能夠被成功接收。但是 5 秒的延遲太長太不講道理了。
所幸的是,Stack Overflow 里的這篇帖子提供了一個有效解決方案。
簡言之就是先忽略第一次點擊按鈕後應用的 UI 反饋:
然後在 System Events 的 語句外面殺掉 System Events 進程:
然後正常進行第二次點擊操作。
完整語句是這樣:
*檢測屏幕內容2
一套自動化流程必定包含許多操作,這些操作之間會有不可避免的等待時間。比如,等待一個應用的主窗口打開。最簡單的方法是自己估計所需的時間,然後用 語句讓 AppleScript 暫停一會兒。然而為了 AppleScript 能夠有效執行,等待時間需比實際時間要長,這樣就不效率了!
更效率的方法,是讓 AppleScript 自己知道什麼時候主窗口出現了。
除了讓 AppleScript 自己檢測窗口的存在,你還可以檢測應用的彈窗內容是不是符合一些特定條件。這就要你自己發揮想像力了。
*AppleScript 的封裝
最後一步,你也可以藉助一些支持 AppleScript 的第三方應用來封裝你的腳本,比如Alfred、Keyboard Maestro等,本文的第一幅動圖中我把記賬的錄入 AppleScript 變成了 Keyboard Maestro 里的一個按鈕,點擊這個按鈕就能執行該腳本。
*GUI Scripting 的一個優點
對 UI 元素進行控制時,並不要求該 UI 元素呈現在屏幕上,即使一個按鈕被其他窗口擋住了,腳本里對它進行的點擊操作也能順利進行。所以,理論上執行 AppleScript 腳本時,你可以不受干擾地繼續在電腦上做其他工作。
尾巴
歡迎評論指出文中未闡述清楚、產生混淆之處。
> 下載少數派 iOS 客戶端、關注少數派公眾號,讓智能設備更好用
※Office 安裝卸載太麻煩?用這個工具幫你解決:Office Tool Plus
※在「蘋果派」看不到 Android 相關的內容?你可以關注這些中文網站和頻道
TAG:少數派 |