2014年1月19日 星期日

[UI Automation] Sikuli 的入門使用

來源自 這裡 
Sikuli是什麼? 
用維基百科上的介紹來說,Sikuli 是一種可視化技術,它可以用來自動化的在一個圖形用戶界面(GUI)上進行操作和測試。而 Sikuli 腳本就是實現這一過程的一種腳本語言。它通過截圖來識別需要操作的圖形界面組件,再通 Jython 來完成操作動作從而實現自動化的操作(或者測試). 說得簡單一點,Sikuli 就是能通過截圖幫助我們自動操作電腦的一種便利的方式。如果想瞭解更多的Sikuli的意義,那就讀一讀 Sikuli 作者的 介紹 吧! 

那 Sikuli 是不是很難學呢?如果不追求精細的操控和精準的方式,那你只需要有一個操作電腦的心,再加上認識幾個英語單詞,就足夠了. 

先從安裝Sikuli開始吧: 
是不是要先檢查一下你的操作系統?不,當然不用,但是也有一樣需要確認,那就是你的電腦上是否安裝了Java呢?不知道如何檢測自己電腦上是否安裝了Java嗎?不要著急,只需要打開 Java官方的檢測網頁,然後根據頁面的指引就能得知自己是否安裝了Java,如果沒有,也將有相應的指引,幫助你安裝好Java. 

然後,得益於 Sikuli 作者的不懈努力,不論是什麼什麼操作系統,只要安裝有 Java,就可以容易的從官方網站上下載通用安裝包來完成安裝了

一點一點的學習Sikuli: 
1. 認識一下Sikuli的IDE 
要打開運行Sikuli的運行環境還有編輯環境,我們需要雙擊安裝完成後Sikuli文件夾裡名稱為“runIDE” (Integrated Development Environment) 的文件。打開之後,Sikuli 的 IDE大概就是這樣(下圖為windows中的式樣,Mac中同此差不多,只是圖標更為精緻): 
 

而我們需要關心的也只有三個地方:可以錄入文字的編輯區域,還有運行按鈕和截圖按鈕. 

2. 從點擊按鈕開始 
我們學習電腦的時候,最先學到的或許就是如何通過點擊按鈕來實現對應的功能了。而對於Sikuli而言,點擊操作同樣是重要的,畢竟GUI中按鈕是實現操作的重要組成. 在Sikuli裡,要實現這個操作也十分簡單,因為你只需要記住 “Click” 這個單詞。沒錯,就是英語的“點擊”一詞。它的代碼也極盡簡單: 
Click(…)

而上面這句代碼中的 “…” ,並不是什麼特別的語言,或者什麼複雜的代碼,而是代表了一個截圖。比如希望Sikuli點擊一下Mac OS左上角的蘋果標示,那麼,這樣的一句代碼就可以達到目的: 
Click()

簡單也很便利! 因為這就是 Sikuli 力求達到的一種直觀的自動化操作的方式了

其它的點擊方式也與此類似,比如右鍵點擊就是:`RightClick(…)`,而雙擊就是:`DoubleClick(…)`。 

3. 尋找按鈕或者圖案 
Sikuli 的本意就是讓某一個計算機程序代替人來做操作,而識別按鈕,或者某一個圖案,也就是一個很重要的部分了。雖然這一點的意義重大,但是,對於在Sikuli上的操作卻可以很容易的實現! 這時候,你只需要認識這樣的一個英文單詞——Find。沒錯,想要在屏幕上找到某一個按鈕或者圖案,只需要使用: 
Find(…)

就可以了。當然,這個函數括號裡的目標依然是某一個東西的截圖。我們可以寫這樣的一個簡單的小命令: 
x=find()
click(x)

那這個例子實現的又是怎樣的操作呢?這個命令其實還是等同於`Click()`,只是這個例子裡,我們關注的是 Sikuli 模仿人行為的過程。一個人來點擊某一個按鈕的過程是:找到按鈕,然後點擊。而通過“find-click”方式完成的 Sikuli 腳本也同樣實現的就是人的操作過程! 如果若們要一個一個找到所有相同的按鈕要怎麼辦?不用擔心,不用寫很多遍`find(…)`的,只需要使用: 
findAll(…)

就可以了。findAll()可以一次性把所有相同按鈕,或者圖案一次性都找到。這樣找到的按鈕就會形成一個集合,這個集合的形成應該很好理解,繼續就是要如何來逐一操作這個按鈕集合裡的按鈕呢?這就涉及到 Sikuli 的程序控制問題了。這也是,接下來要講到的內容. 

4. Sikuli 腳本的程序控制 
那什麼是程序控制呢?那也就是在涉及到重複做某一個操作,或者在判斷某一個條件之後再決定是否要進行某一個操作,以及類似的情況的時候,我們所談論的就是程序控制了. 在 Sikuli 裡面,這個表示條件運行某一個行為的語句就夠也和上面這個例子類似(`#`後是程序註釋內容): 
if … : … #do something

還有另一類程序控制的內容,那就是循環語句了。也就是,需要重複做某一個動作的程序語言命令。在一般的計算機語言裡,一般有兩種方式來完成這樣的重複。一個就是for循環語句,一個是while循環語句. 我們先來分別看看 for循環語句 和 while循環語句 在Sikuli裡的寫法吧: 
* for 循環語句: for i in set: … #do something 
* while 循環語句: while … #condition : … #do something 

從上面的這個結構中,我們很容易瞭解到這樣一件事情:for循環語句是先確定需要循環操作的某一個集合,然後再進行重複操作;而while循環語句則是先考慮某一個條件成立與否來,再決定是否結束重複的操作. 那麼,現在就可以解決上面那個點擊找到的所有相同按鈕的操作了,可以用這樣的代碼來實現: 
for x in findAll(): click(x)

為了做出對比,我們再來分別看一下while循環語句的例子吧. 我們可以舉這樣的一個例子:用Sikuli來實現一下,如果我的某一個 Skype 好友下線了,就提醒我的功能。首先,我們不能確定需要查看好友下沒下限需要多少次,或者是他會在線多久,所以也就不能確定重複次數的集合了,換句話說就是,這個問題,不能使用for循環語句來完成目標。而恰切,這個循環中有一個判斷的條件,也就是關注這個好友的在線狀態是結束於好友下線的瞬間,於是,我們就可以用 while循環語句 來解決這個問題了: 
while exists(): wait(5)
popup(u”vgod下線了”)

這個代碼中,除了while循環語句,還有三個新的功能函數,`exists(…)`函數表示判斷目標截圖是不是存在,放到我們的例子裡就是用來檢查好友 vgod 的skype圖標是否處於在線狀態; `wait(…)`函數表示等待,括號裡填上需要等待的秒數就好; 而最後的`popup(…)`函數就是用於彈出一個帶文字的提示框. 

5. 打開特定的程序 
在模仿我們操作行為上更進一步,就是:打開某個程序,然後在這個程序上進行操作。就比如打開Safari,然後進入Top Sites。對應打開程序這個操作的Sikuli函數依然十分貼近英文: 
App.open(…)

那麼,我們就可以這樣來完成這個例子: 
App.open(“Safari”)
click()

當然這是在Safari還沒打開的情況下,如果Safari打開了,但是,窗口被最小化了,我們又要如何操作呢?同樣簡單,使用 App.focus(…) 就可以了。只需要上面的例子裡的第一行修改成: 
App.focus()

類似的,關閉程序,就是:App.close(…),這個函數的使用方法也是類似的. 

6. 操作鍵盤 
直到上面,我們一直都在關注的都是鼠標操作,現在是我們需要開始關注一下鍵盤操作的時候了. 我們從一開始到現在,已經足夠多的了解到點擊鼠標在 Sikuli 裡是Click(…),而敲擊鍵盤在 Sikuli 裡其實也是差不多的,就是使用: 
type(…)

我們可以做這樣一個例子,就是在Spotlight中搜索一個單詞: 
click()
type(“Sikuli”)

對於普通的文字輸入,只需要把需要的文字用雙引號括起來在寫到 “type(…)” 的括號裡就可以了。如果是中文的話,就在雙引號前加上一個字母“u”: 
type(u”朱麗葉”)

那麼對於特殊字符又要如何處理呢?比如,Mac OS上的 CMD,又或者是 Windows 上的win鍵,這兩個極特殊的鍵,在 Sikuli 裡面都使用 KEY_META 來代表,使用的方法就是直接把它寫入括號內,如:type(KEY_META),注意喲,對於特殊按鍵是不用使用雙引號括起來的

對於 CTRL、ALT 之類的特殊鍵,也可以按照類似的模式使用,也就是“KEY_”加上對應的全大寫鍵名。不過,這個表示方法並不適用於全部特殊鍵。對於 “F1” 至 “F12” 和 “ESC” 鍵而言,需要使用 “Key.” 加上鍵名來表示. 當我們需要同時按下兩個按鍵來完成某一個操作的時候,又要如何在 Sikuli 裡實現呢?雖然還是使用 “type(…)”,但是也只是簡單的稍作增加,比如我們要使用快捷鍵刷新 Safar i的當前頁面. (更多說明可以參考 Key Constants
type(KEY_META,”R”)

7. 一個用於搶購的實例 
當我們已經明白並且記住了以上那些東西之後,就可以考慮做一些稍微複雜的事情了。選擇一個什麼樣子的實例比較有趣呢?我首先想到的,就是這類“手快有手慢沒”的網絡搶購的例子了! 

想想看吧,我們需要Sikuli不停的監視網頁,如果網頁不能實時自刷新、自更新,那麼,還要不斷刷新網頁,直到搶購的時機來到,當開始請購的時候,需要點擊搶購的按鈕,需要修改購買的數量,如果有需要還要填寫自己的地址和信用卡信息等等,一直到確認所有信息,並完成最後的訂單確認. 我們就以下面這個網頁的搶購為例吧! 
 

我們需要等到搶購的按鈕 "" 出現,為此我們假設網頁不能自更新,於是,在Mac OS裡面我們可以用這樣一段代碼實現: 
App.focus(“Safari”)
while not exists():
type(KEY_META,”R”)
click()

然後,在新的頁面上,修改需要搶購的個數(假設買三件),再確認購買進入訂單頁面。當然,也還是有可能需要我們滾動一下頁面來找到需要修改的位置。用 Sikuli 來實現的代碼也就是: 
while not exists():
  type(key.DOWN)
x=find().right().find()
for i in range(3):
  click(x)
click()

在這一段代碼中,兩個新的函數,一個是“right()”,這是用來表示搜索方向的函數;還有一個是“range(…)”,這是用來生成數列的函數,數列長度填入函數的括號內,這是一個 Python 裡的函數. 當我們進入訂單頁面之後,需要檢查是否已經填好地址,如果沒有填好地址,就把地址填上,再確認訂單,我們這次搶購就算完成了。相應的 Sikuli 代碼可以這樣寫出來: 
if exists():
  click()
  type(u”中國哏都”)
  click()
click()

現在,我們就可以把程序完整整理出來了,需要注意的是,Sikuli 在解讀代碼過程中使用的是Python/Jython的解讀模式,也是通過縮進來判斷那些程序是一起運行的。上面的程序中 while循環語句 等程序控制語句我都使用了這樣的方式來分行分別寫下運行條件和運行內容. 

8. 各種Sikuli的小提示 
1. 如果需要截圖的按鈕在比較深的菜單裡,那麼就需要手動啓動 Sikuli 的截圖快捷鍵。這個截圖快捷鍵是:Command+Shift+2 
2. 可以多是用幾個 “wait(…)” 函數來讓 Sikuli 暫停幾秒鐘,尤其是再打開網頁、刷新網頁的時候,因為未加載好的網頁可能讓識別出錯。 
3. Sikuli 自帶函數可操作的對象,大多數都可以使用截圖。雖然使用截圖會導致運行效率略有降低,但是使用截圖才是真正 Sikuli 的核心,所以不要為了速度本末倒置
4. 鼠標的拖拽操作對於 Sikuli 其實也是十分簡單的,只需要記住去使用 “dragDrop(…)” 函數就可以。 
5. Sikuli 是建立在截圖的基礎上的,也就導致,不同機器、不同分辨率、不同操作環境的電腦不能通用一個Sikuli腳本
6. if 條件運行語句的完整結構是: “if …: con1 else: con2”,含義就是如果滿足某一個條件,就運行 con1 的語句,否則,就運行 con2。 
7. 如果有時間,最好完整讀一讀 Sikuli 完整的函數介紹,因為我只是介紹了最為基本的內容,那不是 Sikuli 的全部! 

參考文獻:: 
Sikuli的發佈在2010年,到現在已經有三年的歷史了。但是 Sikuli 的發展並不快,其實它從一發佈就已經足夠完善了。有人說,Sikuli 很像按鍵精靈,嗯,確實是這樣,尤其是初學的時候。但是,當我們需要更複雜的操作的時候,當我們需要更為精緻的操作的時候,我們就會發現 Sikuli 的不同了. 
1. Sikuli (from Wikipedia) 
2. Sikuli Script 
3. Sikuli帶來的意義與無限潛力 
4. 會截圖就會自動化測試 
5. Sikuli常用函數與簡單事件操作. 
6. IDE (from Wikipedia) 
7. Sikuli——創新的圖形化編程技術 
8. Tutorials — Sikuli X 1.0 documentation 
9. Python (from Wikipedia) 
10. Jython入門教程

3 則留言:

  1. 您好,
    現在可以直接在Android 上面使用Sikuli 了
    AnkuLua = Android + Sikuli + Lua
    我們是AnkuLua 開發者
    歡迎試用介紹並給我們指教

    回覆刪除
    回覆
    1. 附上連結:
      https://play.google.com/store/apps/details?id=com.appautomatic.ankulua.trial&hl=zh_TW

      刪除
  2. 你好,我有想找人做一個 sikuli 的程式,模擬點擊。如果你有意願接案或長期配合請 email 給我。mmmayagan@gmail.com

    回覆刪除

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...