只會用Selenium爬網頁?Appium爬App瞭解一下

崔慶才丨靜覓發表於2018-04-16

Appium是一個跨平臺移動端自動化測試工具,可以非常便捷地為iOS和Android平臺建立自動化測試用例。它可以模擬App內部的各種操作,如點選、滑動、文字輸入等,只要我們手工操作的動作Appium都可以完成。在前面我們瞭解過Selenium,它是一個網頁端的自動化測試工具。Appium實際上繼承了Selenium,Appium也是利用WebDriver來實現App的自動化測試。對iOS裝置來說,Appium使用UIAutomation來實現驅動。對於Android來說,它使用UiAutomator和Selendroid來實現驅動。

Appium相當於一個伺服器,我們可以向Appium傳送一些操作指令,Appium就會根據不同的指令對移動裝置進行驅動,完成不同的動作。

對於爬蟲來說,我們用Selenium來抓取JavaScript渲染的頁面,可見即可爬。Appium同樣也可以,用Appium來做App爬蟲不失為一個好的選擇。

下面我們來了解Appium的基本使用方法。

一、本節目標

我們以Android平臺的微信為例來演示Appium啟動和操作App的方法,主要目的是瞭解利用Appium進行自動化測試的流程以及相關API的用法。

二、準備工作

請確保PC已經安裝好Appium、Android開發環境和Python版本的Appium API。另外,Android手機安裝好微信App。

三、啟動App

Appium啟動App的方式有兩種:一種是用Appium內建的驅動器來開啟App,另一種是利用Python程式實現此操作。下面我們分別進行說明。

首先開啟Appium,啟動介面如下圖所示。

只會用Selenium爬網頁?Appium爬App瞭解一下

直接點選Start Server按鈕即可啟動Appium的服務,相當於開啟了一個Appium伺服器。我們可以通過Appium內建的驅動或Python程式碼向Appium的伺服器傳送一系列操作指令,Appium就會根據不同的指令對移動裝置進行驅動,完成不同的動作。啟動後執行介面如下圖所示。

只會用Selenium爬網頁?Appium爬App瞭解一下

Appium執行之後正在監聽4723埠。我們可以向此埠對應的服務介面傳送操作指令,此頁面就會顯示這個過程的操作日誌。

將Android手機通過資料線和執行Appium的PC相連,同時開啟USB除錯功能,確保PC可以連線到手機。

可以輸入adb命令來測試連線情況,如下所示:

adb devices -l複製程式碼

如果出現類似如下結果,這就說明PC已經正確連線手機。

List of devices attached
2da42ac0 device usb:336592896X product:leo model:MI_NOTE_Pro device:leo複製程式碼

model是裝置的名稱,就是後文需要用到的deviceName變數。我使用的是小米Note頂配版,所以此處名稱為MI_NOTE_Pro。

如果提示找不到adb命令,請檢查Android開發環境和環境變數是否配置成功。如果可以成功呼叫adb命令但不顯示裝置資訊,請檢查手機和PC的連線情況。

接下來用Appium內建的驅動器開啟App,點選Appium中的Start New Session按鈕,如下圖所示。

只會用Selenium爬網頁?Appium爬App瞭解一下

這時會出現一個配置頁面,如下圖所示。

只會用Selenium爬網頁?Appium爬App瞭解一下

需要配置啟動App時的Desired Capabilities引數,它們分別是platformNamedeviceNameappPackageappActivity

  • platformName:它是平臺名稱,需要區分Android或iOS,此處填寫Android。

  • deviceName:它是裝置名稱,此處是手機的具體型別。

  • appPackage:它是App程式包名。

  • appActivity:它是入口Activity名,這裡通常需要以 . 開頭。

在當前配置頁面的左下角也有配置引數的相關說明,連結是https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md。

我們在Appium中加入上面4個配置,如下圖所示。

只會用Selenium爬網頁?Appium爬App瞭解一下

點選儲存按鈕,儲存下來,我們以後可以繼續使用這個配置。

點選右下角的Start Session按鈕,即可啟動Android手機上的微信App並進入到啟動頁面。同時PC上會彈出一個除錯視窗,從這個視窗我們可以預覽當前手機頁面,並可以檢視頁面的原始碼,如下圖所示。

只會用Selenium爬網頁?Appium爬App瞭解一下

點選左欄中螢幕的某個元素,如選中登入按鈕,它就會高亮顯示。這時中間欄就顯示了當前選中的按鈕對應的原始碼,右欄則顯示了該元素的基本資訊,如元素的id、class、text等,以及可以執行的操作,如Tap、Send Keys、Clear,如下圖所示。

只會用Selenium爬網頁?Appium爬App瞭解一下

點選中間欄最上方的第三個錄製按鈕,Appium會開始錄製操作動作,這時我們在視窗中操作App的行為都會被記錄下來,Recorder處可以自動生成對應語言的程式碼。例如,我們點選錄製按鈕,然後選中App中的登入按鈕,點選Tap操作,即模擬了按鈕點選功能,這時手機和視窗的App都會跳轉到登入頁面,同時中間欄會顯示此動作對應的程式碼,如下圖所示。

只會用Selenium爬網頁?Appium爬App瞭解一下

接下來選中左側的手機號文字框,點選Send Keys,對話方塊就會彈出。輸入手機號,點選Send Keys,即可完成文字的輸入,如下圖所示。

只會用Selenium爬網頁?Appium爬App瞭解一下

我們可以在此頁面點選不同的動作按鈕,即可實現對App的控制,同時Recorder部分也可以生成對應的Python程式碼。

下面我們看看使用Python程式碼驅動App的方法。首先需要在程式碼中指定一個Appium Server,而這個Server在剛才開啟Appium的時候就已經開啟了,是在4723埠上執行的,配置如下所示:

server = 'http://localhost:4723/wd/hub'複製程式碼

用字典來配置Desired Capabilities引數,程式碼如下所示:

desired_caps = {
    'platformName': 'Android',
    'deviceName': 'MI_NOTE_Pro',
    'appPackage': 'com.tencent.mm',
    'appActivity': '.ui.LauncherUI'
}複製程式碼

新建一個Session,這類似點選Appium內建驅動的Start Session按鈕相同的功能,程式碼實現如下所示:

from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

driver = webdriver.Remote(server, desired_caps)複製程式碼

配置完成後執行,就可以啟動微信App了。但是現在僅僅是可以啟動App,還沒有做任何動作。

再用程式碼來模擬剛才演示的兩個動作:一個是點選“登入”按鈕,一個是輸入手機號。

看看剛才Appium內建驅動器內的Recorder錄製生成的Python程式碼,自動生成的程式碼非常累贅,例如點選“登入”按鈕的程式碼如下所示:

el1 = driver.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.View/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.RelativeLayout/android.widget.Button[1]")
el1.click()複製程式碼

這段程式碼的XPath選擇器路徑太長,選擇方式沒有那麼科學,獲取元素時也沒有設定等待,很可能會有超時異常。所以我們修改一下,將其修改為通過ID查詢元素,設定延時等待,兩次操作的程式碼改寫如下所示:

wait = WebDriverWait(driver, 30)
login = wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/cjk')))
login.click()
phone = wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/h2')))
phone.set_text('18888888888')複製程式碼

綜上所述,完整的程式碼如下所示:

from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

server = 'http://localhost:4723/wd/hub'
desired_caps = {
    'platformName': 'Android',
    'deviceName': 'MI_NOTE_Pro',
    'appPackage': 'com.tencent.mm',
    'appActivity': '.ui.LauncherUI'
}
driver = webdriver.Remote(server, desired_caps)
wait = WebDriverWait(driver, 30)
login = wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/cjk')))
login.click()
phone = wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/h2')))
phone.set_text('18888888888')複製程式碼

一定要重新連線手機,再執行此程式碼,這時即可觀察到手機上首先彈出了微信歡迎頁面,然後模擬點選登入按鈕、輸入手機號,操作完成。這樣我們就成功使用Python程式碼實現了App的操作。

四、API

接下來看看使用程式碼如何操作App、總結相關API的用法。這裡使用的Python庫為AppiumPythonClient,其GitHub地址為https://github.com/appium/python-client,此庫繼承自Selenium,使用方法與Selenium有很多共同之處。

1. 初始化

需要配置Desired Capabilities引數,完整的配置說明可以參考https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md。一般來說,配置幾個基本引數即可,如下所示:

from appium import webdriver

server = 'http://localhost:4723/wd/hub'
desired_caps = {
    'platformName': 'Android',
    'deviceName': 'MI_NOTE_Pro',
    'appPackage': 'com.tencent.mm',
    'appActivity': '.ui.LauncherUI'
}
driver = webdriver.Remote(server, desired_caps)複製程式碼

這裡配置了啟動微信App的Desired Capabilities,這樣Appnium就會自動查詢手機上的包名和入口類,然後將其啟動。包名和入口類的名稱可以在安裝包中的AndroidManifest.xml檔案獲取。

如果要開啟的App沒有事先在手機上安裝,我們可以直接指定App引數為安裝包所在路徑,這樣程式啟動時就會自動向手機安裝並啟動App,如下所示:

from appium import webdriver

server = 'http://localhost:4723/wd/hub'
desired_caps = {
    'platformName': 'Android',
    'deviceName': 'MI_NOTE_Pro',
    'app': './weixin.apk'
}
driver = webdriver.Remote(server, desired_caps)複製程式碼

程式啟動的時候就會尋找PC當前路徑下的APK安裝包,然後將其安裝到手機中並啟動。

2. 查詢元素

我們可以使用Selenium中通用的查詢方法來實現元素的查詢,如下所示:

el = driver.find_element_by_id('com.tencent.mm:id/cjk')複製程式碼

在Selenium中,其他查詢元素的方法同樣適用,在此不再贅述。

在Android平臺上,我們還可以使用UIAutomator來進行元素選擇,如下所示:

el = self.driver.find_element_by_android_uiautomator('new UiSelector().description("Animation")')
els = self.driver.find_elements_by_android_uiautomator('new UiSelector().clickable(true)')複製程式碼

在iOS平臺上,我們可以使用UIAutomation來進行元素選擇,如下所示:

el = self.driver.find_element_by_ios_uiautomation('.elements()[0]')
els = self.driver.find_elements_by_ios_uiautomation('.elements()')複製程式碼

還可以使用iOS Predicates來進行元素選擇,如下所示:

el = self.driver.find_element_by_ios_predicate('wdName == "Buttons"')
els = self.driver.find_elements_by_ios_predicate('wdValue == "SearchBar" AND isWDDivisible == 1')複製程式碼

也可以使用iOS Class Chain來進行選擇,如下所示:

el = self.driver.find_element_by_ios_class_chain('XCUIElementTypeWindow/XCUIElementTypeButton[3]')
els = self.driver.find_elements_by_ios_class_chain('XCUIElementTypeWindow/XCUIElementTypeButton')複製程式碼

但是此種方法只適用於XCUITest驅動,具體可以參考:https://github.com/appium/appium-xcuitest-driver。

3. 點選

點選可以使用tap()方法,該方法可以模擬手指點選(最多五個手指),可設定按時長短(毫秒),程式碼如下所示:

tap(self, positions, duration=None)複製程式碼

其中後兩個引數如下。

  • positions:它是點選的位置組成的列表。

  • duration:它是點選持續時間。

例項如下所示:

driver.tap([(100, 20), (100, 60), (100, 100)], 500)複製程式碼

這樣就可以模擬點選螢幕的某幾個點。

對於某個元素如按鈕來說,我們可以直接呼叫cilck()方法實現模擬點選,例項如下所示:

button = find_element_by_id('com.tencent.mm:id/btn')
button.click()複製程式碼

4. 螢幕拖動

可以使用scroll()方法模擬螢幕滾動,用法如下所示:

scroll(self, origin_el, destination_el)複製程式碼

可以實現從元素origin_el滾動至元素destination_el

它的後兩個引數如下。

  • original_el:它是被操作的元素。

  • destination_el:它是目標元素。

例項如下所示:

driver.scroll(el1,el2)複製程式碼

可以使用swipe()模擬從A點滑動到B點,用法如下所示:

swipe(self, start_x, start_y, end_x, end_y, duration=None)複製程式碼

後面幾個引數說明如下。

  • start_x:它是開始位置的橫座標。

  • start_y:它是開始位置的縱座標。

  • end_x:它是終止位置的橫座標。

  • end_y:它是終止位置的縱座標。

  • duration:它是持續時間,單位是毫秒。

例項如下所示:

driver.swipe(100, 100, 100, 400, 5000)複製程式碼

這樣可以實現在5s時間內,由(100, 100)滑動到 (100, 400)。

可以使用flick()方法模擬從A點快速滑動到B點,用法如下所示:

flick(self, start_x, start_y, end_x, end_y)複製程式碼

幾個引數說明如下。

  • start_x:它是開始位置的橫座標。

  • start_y:它是開始位置的縱座標。

  • end_x:它是終止位置的橫座標。

  • end_y:它是終止位置的縱座標。

例項如下所示:

driver.flick(100, 100, 100, 400)複製程式碼

5. 拖曳

可以使用drag_and_drop()將某個元素拖動到另一個目標元素上,用法如下所示:

drag_and_drop(self, origin_el, destination_el)複製程式碼

可以實現將元素origin_el拖曳至元素destination_el

兩個引數說明如下。

  • original_el:它是被拖曳的元素。

  • destination_el:它是目標元素。

例項如下所示:

driver.drag_and_drop(el1, el2)複製程式碼

6. 文字輸入

可以使用set_text()方法實現文字輸入,如下所示:

el = find_element_by_id('com.tencent.mm:id/cjk')
el.set_text('Hello')複製程式碼

7. 動作鏈

與Selenium中的ActionChains類似,Appium中的TouchAction可支援的方法有tap()press()long_press()release()move_to()wait()cancel()等,例項如下所示:

el = self.driver.find_element_by_accessibility_id('Animation')
action = TouchAction(self.driver)
action.tap(el).perform()複製程式碼

首先選中一個元素,然後利用TouchAction實現點選操作。

如果想要實現拖動操作,可以用如下方式:

els = self.driver.find_elements_by_class_name('listView')
a1 = TouchAction()
a1.press(els[0]).move_to(x=10, y=0).move_to(x=10, y=-75).move_to(x=10, y=-600).release()
a2 = TouchAction()
a2.press(els[1]).move_to(x=10, y=10).move_to(x=10, y=-300).move_to(x=10, y=-600).release()複製程式碼

利用以上API,我們就可以完成絕大部分操作。更多的API操作可以參考:https://testerhome.com/topics/3711。

五、結語

本節中,我們主要了解了Appium的操作App的基本用法,以及常用API的用法。



本資源首發於崔慶才的個人部落格靜覓: Python3網路爬蟲開發實戰教程 | 靜覓

如想了解更多爬蟲資訊,請關注我的個人微信公眾號:進擊的Coder

weixin.qq.com/r/5zsjOyvEZ… (二維碼自動識別)


相關文章