介面進階操作¶
本章節為您介紹更深層的自動化介面,您可以透過這些介面來完成各種細緻的操作,本章的內容較多,如果您是第一次接觸,我們建議您耐心地看完每個節點。
小撇步
取得元素¶
您在基礎知識或前文中可能已經對它有一些了解了,您需要透過選擇器來找到相關的元素才能進行操作。您應該也看到了在什麼地方可以取得選擇器參數。現在我們下面的一些介紹將圍繞著這個元素進行。您可以在這張圖片的右側看到「同意」這個元素的相關資訊。

注意
對於以上元素,我們取得它一般是透過 text,使用 text 的條件是目前的介面沒有另一個元素的 text 也是「同意」,這是最簡便的方法。其次您也可以選用 resourceId,不過您需要注意這裡的 resourceId 代表的並不是唯一 ID,它代表的是資源 ID,而一個介面內可能包含很多個相同資源 ID 的元素。其他的一些如 packageName、checkable 等一般不常用,但如果在 text、resourceId、description 等都沒有的情況下,可以嘗試使用這些欄位。我們可以透過如下幾種方式取得這個元素。
element = d(text="同意")
element = d(text="同意", resourceId="com.tencent.news:id/btm_first_agree")
element = d(resourceId="com.tencent.news:id/btm_first_agree")
元素點擊¶
呼叫如下介面進行一次普通的元素點擊操作,上下文中將會為您實現手動點擊「同意」的效果。
element.click()
如果您需要指定點擊元素的位置,您可以指定 corner,Corner.COR_CENTER 代表點擊該元素的中心點,您也可以點擊它的左上角或右下角(COR_BOTTOMRIGHT)。
element.click_exists(corner=Corner.COR_TOPLEFT)
在該元素上執行長按操作,不存在則拋出例外。該介面也支援 corner,無法指定長按時間。
element.long_click()
元素存在則點擊,如果元素不存在,呼叫此介面不會引發例外。該介面同樣支援 corner。
element.click_exists()
>>> element.click_exists()
True
是否存在¶
很多情況下,在進一步操作時需要對元素的存在性進行檢查,否則後續流程可能會出現例外,或在錯誤的介面操作錯誤的事情。您可能需要在某些情況下使用如下介面進行存在性判斷。
element.exists()
元素資訊¶
一些情況下,您可能會想要取得元素的部分資訊,例如您可能會想要得到元素對應的座標、區域,或元素上包含的文字或描述等字串資訊。您可以透過如下介面來讀取元素資訊。
element.info()
在我們上述的測試元素中,這個測試元素輸出的資訊為:
>>> info = element.info()
>>> print (info)
bounds { ... }
className: "android.widget.TextView"
clickable: true
enabled: true
focusable: true
packageName: "com.tencent.news"
resourceName: "com.tencent.news:id/btn_first_agree"
text: "\345\220\214\346\204\217"
visibleBounds { ... }
提示
可以看到這個資訊相對來說還是有點複雜的,這是 protobuf 預設的列印格式,您可以直接透過存取對應的屬性來列印出其實際的值。例如想要讀取元素 text 的值,您可以直接像下面這樣使用。
>>> info = element.info()
>>> print (info.text)
同意
當然,裡面還有一些元素區域座標相關的資訊,您也可以存取它們。例如您現在想要取得該元素對應的區域資訊,您可以像下面這樣使用來列印區域資訊,您也可以將其取得為後續操作的變數。
>>> info = element.info()
>>> print (info.bounds)
輸出或返回的值是一個區域資訊(Bound),您後面會發現這是某個截圖介面也會用到的參數。是的,您可以將這個參數提交給截圖介面來實現為這個元素單獨截圖,不過我們早已為您封裝好了。
您可能也想要取得元素的寬度和高度用來計算某些偏移,例如計算其他相對元素的偏移,您可以:
>>> info = element.info()
>>> print (info.bounds.width, info.bounds.height)
484 138
或者,取得該元素的中心點,或角點如左上角、右下角這種。當然,以下介面通常返回的都是 Point 資訊,您也可以從 Point 物件中取得對應的 X、Y 軸裝置螢幕座標。
>>> info = element.info()
>>> print (info.bounds.center())
x: 792
y: 1908
>>> print (info.bounds.center().x)
792
以下呼叫用來取得元素的角點座標,範例取得了元素左上角的座標,除此之外還支援取得如 bottom-right、top-right、bottom-left 等共四個角點的座標。
>>> info = element.info()
>>> print (info.bounds.corner("top-left"))
x: 550
y: 1839
>>> print (info.bounds.corner("top-left").x)
550
元素遍歷¶
您也可以遍歷選擇器選擇到的所有元素。正常情況下,上下文中這個元素可能只有一個,所以如果您測試,請選擇其他選擇器進行測試,直接在選擇器上使用 for 迴圈或其他方式進行遍歷即可。
for i in element: print (i)
或者如果您知道它存在多個匹配元素,想取得指定的第 N 個匹配元素,可以使用如下介面取得。
element_3rd = element.get(3)
元素計數¶
通常情況下您不會直接用到此介面,以下呼叫可以取得您目前選擇器匹配到的元素個數。
>>> element.count()
1
元素截圖¶
我們支援您進行元素級別的截圖,可以單獨截下元素的圖像而無需全螢幕截圖再行裁剪。
element.screenshot(quality=60)
您可以在截圖後直接使用 getvalue 來取得截圖的二進位資料,或直接將其傳入 PIL Image。
>>> element.screenshot(quality=60).getvalue()
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xe2\x02(ICC_PROFILE\x00\x01\x01\x00\x00\x02\x18\x00\x00\x00\x00\x02\x10\x00\x00mntrRGB XYZ \x00\x00...
或者如果您無需繼續處理,也可以選擇直接將截圖儲存到本機檔案中。
>>> element.screenshot(quality=60).save("image.png")
等待元素¶
一些情況下,您可能需要判斷目前頁面是否載入完畢。通常情況下,您可以透過判斷相關元素是否已經顯示來判斷目前頁面是否已經載入完成。如下範例會等待「同意」元素出現,最長等待時間為 10 秒。
提示
element.wait_for_exists(10*1000)
>>> element.wait_for_exists(10*1000)
True
當然,我們不只支援您等待元素出現,也支援等待元素消失,也就是說一直到元素從介面消失。
element.wait_until_gone(10*1000)
>>> element.wait_until_gone(10*1000)
False
文字輸入¶
文字輸入相對來說是一個較需要注意的地方,我們不可能往一個同意按鈕上輸入文字,因為那是按鈕。現在我們重新拿一個輸入框元素來介紹,這個元素的基本資訊如下所示。

注意
提示
對於上面這個輸入框,我們可以呼叫如下介面來向輸入框輸入「你好世界」這個字串,當然也支援您輸入英文或其他 unicode 字串,您只需要像下面這樣使用即可在框內輸入文字。
>>> element = d(text="搜索感兴趣的内容")
>>> element.set_text("你好世界")
True
或者,您突發奇想,又想要取得這個輸入框目前顯示的文字內容,那麼您可以這樣呼叫。
注意
>>> element = d(className="android.widget.EditText")
>>> element.get_text()
'你好世界'
又或者是清空目前輸入的內容。通常輸入文字會自動清空之前的文字,但是您也可以手動清空。
提示
>>> element = d(className="android.widget.EditText")
>>> element.clear_text_field( )
True
備註
普通滑動¶
使用如下介面來進行介面的滑動操作,例如列表的上下滑動翻頁。以下呼叫實現向上滑動,step 自行調整,越大滑動速度會越慢,比較適合精度要求較高的滑動。
注意
d().swipe(direction=Direction.DIR_UP, step=32)
>>> element = d(resourceId="com.tencent.news:id/important_list_content")
>>> element.swipe(direction=Direction.DIR_UP, step=32)
True
快速滑動¶
快速滑動類似人快速滑動螢幕的行為,此操作會快速地滑動螢幕,適合模擬快速瀏覽類的操作。以下範例從上往下滑動螢幕,範例中選擇器為空,您仍然需要根據實際情況選擇是否填寫選擇器。
d().fling_from_top_to_bottom()
從下往上的快速滑動
d().fling_from_bottom_to_top()
從左往右的快速滑動
d().fling_from_left_to_right()
從右往左的快速滑動
d().fling_from_right_to_left()
注意
>>> element = d(resourceId="com.tencent.news:id/important_list_content")
>>> element.fling_from_bottom_to_top()
True
正在更新...
其他操作¶
# 將此 APP 拖動歸類到「購物」資料夾(依據實際情況修改)
element.drag_to(Selector(text="購物"))
#########
# 尋找同級或子級元素
#########
# 有時候會有一些重複元素或無明顯特徵的元素,很難去定位
# 這時你可以透過尋找子級/同級元素的方法來縮小尋找範圍
# 子級元素,舉例為:一個聊天登入框,裡面的輸入框即為登入框的子級元素
# 同級元素,舉例為:聊天輸入框裡面的使用者名稱和密碼框為同級元素(正常情況下)
form = d(resourceId="login_form")
form.child(index=1)
# 這將取得 login_form 下 index 為 1 的元素
form.child(index=1).sibling()
# 你也可以這樣來找與 login_form 同級的「找回密碼」按鈕
#(其實已經可以透過字串判斷了,就不需要這樣做了,這裡只是示範)
form.sibling(textContains="找回密码")
# 它們本身就是一個 element,你可以對其做任何 element 的操作
# 其他,一直向下/左/右/上滑,直到滑動到底
# 因為並不是一定可以滑動到底或偵測到滑動到底
# 所以 max_swipes 參數是必須的
d().fling_from_top_to_bottom_to_end(max_swipes=32)
d().fling_from_bottom_to_top_to_end(max_swipes=32)
d().fling_from_left_to_right_to_end(max_swipes=32)
d().fling_from_right_to_left_to_end(max_swipes=32)
#########
# scroll: 比較機械性的滑動
#########
step = 60
max_swipes = 32
# 從上往下滑動 step 步
d().scroll_from_top_to_bottom(step)
# 從下往上滑動 step 步
d().scroll_from_bottom_to_top(step)
# 從左往右滑動 step 步
d().scroll_from_left_to_right(step)
# 從右往左滑動 step 步
d().scroll_from_right_to_left(step)
# 其他,一直向下/左/右/上滑,直到滑動到底
# 同上文 fling 描述
d().scroll_from_top_to_bottom_to_end(max_swipes, step)
d().scroll_from_bottom_to_top_to_end(max_swipes, step)
d().scroll_from_left_to_right_to_end(max_swipes, step)
d().scroll_from_right_to_left_to_end(max_swipes, step)