Py爬蟲之Appium自動化

2022-02-05 千世筆記

Appium是一個開源的,適用於原生或混合移動應用( hybrid mobile apps )的自動化測試工具,Appium應用WebDriver: JSON wire protocol驅動安卓和iOS移動應用。

也可以用來爬取App數據,本文將以Android為例。

* 通信

· 由程式設計師編寫的自動化程序(Appium客戶端庫)通過HTTP協議與Appium Server進行通信

· 再由Appium Server與設備的自動化代理進行通信

· 設備的自動化代理接收到指令後執行指令,返回執行後的結果給Appium Server


* 自動化程序

· 自動化程序由程式設計師開發,實現具體的自動化功能

· 要發出具體指令控制設備,需要使用到客戶端庫

· 調用這些庫向設備發送自動化指令


* Appium Server

· Appium Server負責管理設備的自動化環境

· 轉發程序發來的指令給設備,轉發設備被發來的響應給程序


* 設備

· 設備由手機、平板、手邊等組成 (Android、IOS)

· 需要在設備上安裝自動化代理程序,代理程序會等待自動化指令,並執行指令


* 環境下載

在公眾號後臺回復"Appium"獲取全部環境的下載地址

pip install appium-python-client


下載地址

https://github.com/appium/appium-desktop/releases/tag/v1.21.0
https://github.com/appium/appium-desktop/releases/download/v1.21.0/Appium-windows-1.21.0.exe


環境變量

將Appium的安裝路徑添加到系統變量Path中即可


下載地址

在官網下載需要註冊登錄 可在後臺回復 「JDK」獲取下載連結

https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html


環境變量

創建新的系統變量,變量名為: JAVA_HOME 變量值為: JDK的安裝路徑

將下方字符添加到系統變量Path中

%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin

打開cmd輸入 java 有反饋則環境安裝完成


下載

在公眾號後臺回復"SDK"獲取下載連結

(直接放連結怕過期,官方安裝方法相對複雜)


環境配置

創建系統變量 ANDROID_HOME

將下載到的壓縮包解壓並將解壓後的目錄作為變量值保存

將下方字符添加到系統變量Path中

%ANDROID_HOME%\platform-tools


手機端設置

這裡以小米手機為例

在設置 > 我的設備 > 全部參數 中找到MIUI版本 連續點擊5次進入開發者模式


在設置 > 更多設置 > 開發者選項 中打開USB調試


電腦端配置

將手機通過數據線連接到電腦

打開cmd輸入 adb devices 列出設備

手機端如彈出窗口要點擊確定或允許


手機端配置

這裡以夜神模擬器為例

在設置 > 關於平板電腦 中找到版本號 連續點擊5次進入開發者模式

在開發者選項中打開USB調試即可

電腦端配置

將夜神模擬器安裝路徑下的bin目錄添加到系統變量Path中

刪除該目錄下的 nox_adb.exe

將 androidsdk目錄下的platform-tools\adb.exe 

複製到夜神模擬器的bin目錄中並重命名為nox_adb.exe

使用powershell進行如下操作(記得打開模擬器)

cd D:\install\Nox\bin    nox_adb.exe connect 127.0.0.1:62001    nox_adb.exe devices      

重啟模擬器 再打開cmd輸入 adb devices 列出設備



軟體基本配置

在Appium高級設置中有三個需要注意的參數

伺服器地址為0.0.0.0時表示本機的所有IP

伺服器埠為Appium Server部署的埠 一般默認就行

啟動埠在多設備並發的時候會用到

如果你的環境配置沒有問題,在編輯配置中可以看到JDK與SDK的環境變量值


基本配置

啟動會話後點擊右上角的啟動檢查器會話

再配置完指定的參數後可以看到App的布局與控制項信息

這裡以嗶哩嗶哩為例,先在模擬器中打開軟體

打開cmd輸入下方命令獲取軟體包名與入口

adb shell dumpsys activity | findstr "mResume"

將會話信息配置為如下示例

配置完成後啟動會話即可

{  "platformName": "Android",    # 系統名稱(Android/IOS)  "platformVersion": "10",      # 系統版本號(安卓10)  "deviceName": "k30pro",       # 設備名稱隨意  "appPackage": "tv.danmaku.bili",  # APP包名  "appActivity": "MainActivityV2",  # APP入口  "noReset": true,  # 為false時每次啟動都會重置APP,為true時保留Session不重置  "unicodeKeyboard": true,    # 使用unicodeKeyboard的編碼方式來發送字符串  "resetKeyboard": true      # 執行完成後恢復到原來的輸入法}


獲取元素信息

啟動會話後會重啟App並在Appium檢查器會話中顯示App的布局與控制項信息

通過滑鼠選擇某個元素後可以看到元素的屬性與值

可以使用元素的accessibility id 、id 、xpath 等屬性進行定位

目前記住元素的一些屬性信息大概在什麼的地方可以看到就行了

在下方會進行詳細的介紹

除了使用Appium獲取元素信息,還可以使用AndroidSDK中自帶的工具

androidsdk\tools\bin\uiautomatorviewer.bat


常用的一些方法

click()        tap()          send_keys("Hello")    swipe(start_x=x, start_y=y1, end_x=x, end_y=y2, duration=800)  press_keycode()       open_notifications()  quit()                x=driver.get_window_size()['width']    y=driver.get_window_size()['height']   

更多的按鍵信息可以到下放網站中查看

https://github.com/appium/python-client/blob/master/appium/webdriver/extensions/android/nativekey.py

from appium.webdriver.extensions.android.nativekey import AndroidKey
press_keycode(AndroidKey.ENTER)    # 回車press_keycode(AndroidKey.BACK)     # 返回press_keycode(AndroidKey.HOME)     # home鍵press_keycode(AndroidKey.VOLUME_UP)  # 音量+press_keycode(AndroidKey.SPACE)    # 空格press_keycode(AndroidKey.DEL) # 刪除

可以通過下方的方法定位到指定元素,對其進行點擊、輸入、獲取文本等操作

具體的使用方法與Selenium類似 (建議先學Selenium)

find_elements_by_id()       find_elements_by_xpath()    find_elements_by_class_name()    find_elements_by_accessibility_id()    

find_elements find_element

獲取元素的屬性 (如文本、坐標、大小的等)

text            tag_name        size            location        get_attribute("name")      get_attribute(屬性名)    

  - 它可以通過命令行與安卓設備進行交互,如安裝調試應用、傳輸文件等  - 命令參考: https://developer.android.google.cn/studio/command-line/adb.html  - 使用os.system() 來調用  - 使用subprocess 來調用    adb devices -l        adb shell dumpsys activity | findstr "mResume"  adb shell ls /sdcard  adb push wv.apk /sdcard/wv.apk    adb pull /sdcard/new.txt          adb install xx.apk                adb shell    adb shell screencap /sdcard/screen.png    adb shell screenrecord /sdcard/demo.mp4    



獲取App基本信息

通過 命令獲取App的包名與入口,將信息填寫到配置文件中

adb shell dumpsys activity | findstr "mResume"

from appium import webdriverfrom appium.webdriver.extensions.android.nativekey import AndroidKeyimport time
caps = {    "platformName": "Android",         "platformVersion": "7",            "deviceName": "moniqi",         "appPackage": "tv.danmaku.bili",     "appActivity": "MainActivityV2",  "newCommandTimeout":1800, "noReset": "true", "unicodeKeyboard": "true", "resetKeyboard": "true" }
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)

獲取App元素的信息

啟動Appium中的檢查器會話,在配置完成後啟動會話

這邊以搜索框為例,可以看到搜索框的id為 tv.danmaku.bili:id/expand_search

可以簡寫為 expand_search

driver.find_element_by_id("expand_search")

可以看到搜索框的content-desc值為"搜索"

find_elements_by_accessibility_id("搜索")

也可以通過xpath定位

driver.find_element_by_xpath(//android.widget.TextView[@content-desc="搜索"])

與元素進行交互

使用 click() 方法點擊搜索框

driver.find_element_by_id("expand_search").click()

通過手動點擊搜索框後彈出一個新的頁面,這個才是真正的搜索框

接下來使用id定位到搜索框(也可以使用其它方法定位)

driver.find_element_by_id("search_src_text")

定位到搜索框後使用send_keys()方法輸入字符

driver.find_element_by_id("search_src_text").send_keys("Hello")driver.press_keycode(AndroidKey.ENTER)   # 回車

獲取App信息

定位到你要獲取的元素後使用text屬性輸出

# 注意這邊使用的是elements
title_list = driver.find_elements_by_id("title")    # 定位到視頻標題(返回列表)if title_list: # 如果返回的數據不為空時 for title in title_list: print(title.text) # 將其輸出出來

完整代碼

from appium import webdriverfrom appium.webdriver.extensions.android.nativekey import AndroidKeyimport time
caps = { "platformName": "Android", "platformVersion": "7", "deviceName": "k30pro", "appPackage": "tv.danmaku.bili", "appActivity": ".MainActivityV2",     "newCommandTimeout":1800,      "noReset": "true", "unicodeKeyboard": "true", "resetKeyboard": "true" }
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)
driver.find_element_by_id("expand_search").click() driver.find_element_by_id("search_src_text").send_keys("Hello") driver.press_keycode(AndroidKey.ENTER) time.sleep(2) title_list = driver.find_elements_by_id("title") if title_list: for title in title_list: print(title.text)

x1 y1為起始點 x2 y2 為終點,t為起點到終點所花費的時間

注意: 原點坐標(0,0)位於屏幕左上角

swipe(x1, y1, x2, y1, t)
swipe(810,1135,810,2000,1)  # x軸不變y軸向上運動

先獲取屏幕大小再進行滑動

將其封裝方便調用

class Swip:    def __init__(self,driver,xy):        self.driver = driver        self.xy = xy                    self.x = self.xy["width"]           self.y = self.xy["height"]   
def swip_Lift(self,t=500,n=1): x1 = self.x * 0.75 y1 = self.y * 0.5 x2 = self.x * 0.25
for i in range(n): time.sleep(0.2) self.driver.swipe(x1, y1, x2, y1, t) print(f"[+]向左滑動{i+1}次完成")
def swip_Right(self,t=500,n=1): x1 = self.x * 0.25 y1 = self.y * 0.5 x2 = self.x * 0.75
for i in range(n): time.sleep(0.2)             self.driver.swipe(x1, y1, x2, y1, t)  print(f"[+]向右滑動{i+1}次完成")
def swip_Up(self,t=500,n=1): x1 = self.x * 0.25 y1 = self.y * 0.75 y2 = self.y * 0.5
for i in range(n): time.sleep(0.2)             self.driver.swipe(x1, y1, x1, y2, t)  print(f"[+]向上滑動{i+1}次完成")
def swip_Down(self,t=500,n=1): x1 = self.x * 0.25 y1 = self.y * 0.5 y2 = self.y * 0.75
for i in range(n): time.sleep(0.2)             self.driver.swipe(x1, y1, x1, y2, t)  print(f"[+]向下滑動{i+1}次完成")

from appium import webdriverfrom appium.webdriver.extensions.android.nativekey import AndroidKeyimport time
caps = { "platformName": "Android", "platformVersion": "7", "deviceName": "moniqi", "appPackage": "tv.danmaku.bili", "appActivity": "MainActivityV2", "newCommandTimeout":1800, "noReset": "true", "unicodeKeyboard": "true", "resetKeyboard": "true" }

class Swip: def __init__(self, driver, xy): self.driver = driver self.xy = xy self.x = self.xy["width"] self.y = self.xy["height"]
def swip_Lift(self, t=500, n=1): x1 = self.x * 0.75 y1 = self.y * 0.5 x2 = self.x * 0.25
for i in range(n): time.sleep(0.2) self.driver.swipe(x1, y1, x2, y1, t) print(f"[+]向左滑動{i + 1}次完成")
def swip_Right(self, t=500, n=1): x1 = self.x * 0.25 y1 = self.y * 0.5 x2 = self.x * 0.75
for i in range(n): time.sleep(0.2)             self.driver.swipe(x1, y1, x2, y1, t)   print(f"[+]向右滑動{i + 1}次完成")
def swip_Up(self, t=500, n=1): x1 = self.x * 0.25 y1 = self.y * 0.75 y2 = self.y * 0.5
for i in range(n): time.sleep(0.2)             self.driver.swipe(x1, y1, x1, y2, t)  
def swip_Down(self, t=500, n=1): x1 = self.x * 0.25 y1 = self.y * 0.5 y2 = self.y * 0.75
for i in range(n): time.sleep(0.2)             self.driver.swipe(x1, y1, x1, y2, t)   print(f"[+]向下滑動{i + 1}次完成")
if __name__ == "__main__": print("***程序執行開始***") driver = webdriver.Remote("http://localhost:4723/wd/hub", caps) print("[+]基本環境啟動完成") xy = driver.get_window_size() print("[+]屏幕尺寸獲取完成", xy) driver.find_element_by_id("expand_search").click() print("[+]搜索框點擊完成") in_data = input("[*]要爬取的內容 >>>") time.sleep(2) driver.find_element_by_id("search_src_text").send_keys(in_data) print("[+]搜索內容輸入完成") driver.press_keycode(AndroidKey.ENTER) print("[+]搜索執行完成")
swip = Swip(driver, xy) time.sleep(2) num = 1 data = {}
while num <= 5: title_list = driver.find_elements_by_id("title") upuser_list = driver.find_elements_by_id("upuser")
if title_list and upuser_list: for title, upuser in zip(title_list, upuser_list): data[title.text] = upuser.text
swip.swip_Up(n=2) time.sleep(1) print(f"[+]第{num}頁爬取完成") num += 1 else: print("[*]沒有數據") break
print("\n**********數據爬取結束**********") print(f"[*]一共獲取到數據{len(data.keys())}條\n") if data: for title,upuser in data.items(): print(upuser + " --> " + title)
if input("\n輸入 q 退出程序 >>>") == "q": driver.quit()


理論

· 每個Appium Server只能支持一個設備,所以要開啟多個Appium

· 將Appium的服務埠與Android啟動埠進行修改

· 利用UDID參數進行區分多個設備

· 多設備並發一般用於模擬操作

Appium Server

啟動多個Appium後將其伺服器埠與Android啟動埠進行修改

這裡啟動兩個Appium Server

伺服器埠 4723安卓啟動埠 4724
伺服器埠 4725安卓啟動埠 4726

配置參數

啟動兩臺模擬器後查看設備的UDID

在代碼中主要修改的兩個地方如下

caps = {        "udid":127.0.0.1:62001,    "systemPort": 4724    # Android啟動埠}driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)

# 設備2caps = { # 省略部分代碼    "udid":127.0.0.1:62025,    "systemPort": 4726}driver = webdriver.Remote("http://127.0.0.1:4725/wd/hub", caps)

完整代碼

利用多進程實現並發

from appium import webdriverfrom appium.webdriver.extensions.android.nativekey import AndroidKeyimport timeimport multiprocessing
class Swip: def __init__(self, driver, xy): self.driver = driver self.xy = xy self.x = self.xy["width"] self.y = self.xy["height"]
def swip_Lift(self, t=500, n=1): x1 = self.x * 0.75 y1 = self.y * 0.5 x2 = self.x * 0.25
for i in range(n): time.sleep(0.2) self.driver.swipe(x1, y1, x2, y1, t) print(f"[+]向左滑動{i + 1}次完成")
def swip_Right(self, t=500, n=1): x1 = self.x * 0.25 y1 = self.y * 0.5 x2 = self.x * 0.75
for i in range(n): time.sleep(0.2)             self.driver.swipe(x1, y1, x2, y1, t)   print(f"[+]向右滑動{i + 1}次完成")
def swip_Up(self, t=500, n=1): x1 = self.x * 0.25 y1 = self.y * 0.75 y2 = self.y * 0.5
for i in range(n): time.sleep(0.2)             self.driver.swipe(x1, y1, x1, y2, t)  
def swip_Down(self, t=500, n=1): x1 = self.x * 0.25 y1 = self.y * 0.5 y2 = self.y * 0.75
for i in range(n): time.sleep(0.2)             self.driver.swipe(x1, y1, x1, y2, t)   print(f"[+]向下滑動{i + 1}次完成")
def auto(udid,bport,sport): caps = { "platformName": "Android", "platformVersion": "7", "deviceName": "moniqi", "udid": udid, "systemPort": bport, "appPackage": "tv.danmaku.bili", "appActivity": "MainActivityV2", "newCommandTimeout": 1800, "noReset": "true", "unicodeKeyboard": "true", "resetKeyboard": "true" }
print("***程序執行開始***") driver = webdriver.Remote(f"http://localhost:{sport}/wd/hub", caps) print("[+]基本環境啟動完成") xy = driver.get_window_size() print("[+]屏幕尺寸獲取完成", xy) driver.find_element_by_id("expand_search").click() print("[+]搜索框點擊完成") time.sleep(2) driver.find_element_by_id("search_src_text").send_keys("Hello") print("[+]搜索內容輸入完成") driver.press_keycode(AndroidKey.ENTER) print("[+]搜索執行完成")
swip = Swip(driver, xy) time.sleep(2) num = 1 data = {}
while num <= 5: title_list = driver.find_elements_by_id("title") upuser_list = driver.find_elements_by_id("upuser")
if title_list and upuser_list: for title, upuser in zip(title_list, upuser_list): data[title.text] = upuser.text
swip.swip_Up(n=2) time.sleep(1) print(f"[+]第{num}頁爬取完成") num += 1 else: print("[*]沒有數據") break
print("\n**********數據爬取結束**********") print(f"[*]一共獲取到數據{len(data.keys())}條\n") if data: for title, upuser in data.items(): print(upuser + " --> " + title)
if __name__ == "__main__": multiprocessing.Process(target=auto,args=("127.0.0.1:62001","4724","4723")).start()    multiprocessing.Process(target=auto,args=("127.0.0.1:62025","4726","4725")).start()


相關焦點

  • 【appium】appium自動化入門之ios軟體如何測試
    上篇文章寫到appium在Mac上的環境搭建,這篇進入正文,如何在Mac端的appium上測試你的ios產品app端的文章如下:第一類:【appium】appium自動化入門之環境搭建(上)第二類:【appium】appium自動化入門之API(上)書接上文:【appium】appium自動化入門之Mac端(蘋果電腦的福音)看前提醒一下
  • 從零入門:Appium自動化測試iOS Demo
    可以到官網下載對於的appium哦:http://appium.io 6.python開發腳本好吧,其實我也不會python,在網上查到很多自動化測試腳本都用的python寫的,所以我也就邊學習,邊寫腳本呢。
  • Appium自動化測試環境搭建
    ,支持跨平臺,支持多種程式語言,可用於原生,混合和移動web應用程式,使用webdriver驅動ios,android應用程式、那麼為了學習app自動化測試首要任務肯定就是搭建測試開發環境, 因此在這裡記一次搭建Appium自動化測試環境的完整過程,文章較長,需要花費一定的時間,請耐心閱讀,如果文中有什麼錯誤請指正安裝Java JDKJDK環境可以看我之前安裝Jenkins時的隨筆
  • Android Appium自動化測試實踐
    可以在https://bitbucket.org/appium/appium.app/downloads/ 下載安裝包,目前最新包AppiumForWindows_1_4_16_1,沒再支持更新,如果需要有Appium desktop版本,目前最新版是V1.11.0  3.安裝Java JD
  • 爬蟲代理之appium
    #coding:utf-8#Appium 是一個跨平臺移動端向動化測試工具,可以非常便捷地為iOS 和Android 平臺創建自動化測試用例
  • App自動化測試 | Appium 介紹及環境安裝
    Appium是一個可用於測試iOS、 Android作業系統和Windows桌面平臺原生應用,移動網頁應用和混合應用的自動化測試框架
  • Appium+python自動化17-啟動iOS模擬器APP源碼案例
    cd /git_test_app$ git clone https://github.com/appium/sample-code.git 二、啟動appium1.確保appium是啟動狀態,如下左圖2.確保iOS模擬器是啟動狀態,如下右圖
  • appium+python自動化36-android7.0連不上的問題
    前言由於最近很多android手機升級到7.0系統了,有些小夥伴的appium版本用的還是1.4版本,在運行android7.0的app自動化時候遇到無法啟動問題
  • 自動化工具之Appium工具簡單介紹
    背景        自動化,性能測試,接口測試,開發平臺等工作,到底測試的價值在哪裡,其實價值來源不斷充實與為大眾服務,今天簡單介紹ui小工具appium
  • 記一次搭建Appium自動化測試環境的完整過程
    應用程式、那麼為了學習app自動化測試首要任務肯定就是搭建測試開發環境, 因此在這裡記一次搭建Appium自動化測試環境的完整過程,文章較長,需要花費一定的時間,請耐心閱讀,如果文中有什麼錯誤請指正  JDK環境可以看我之前安裝Jenkins時的隨筆https://www.cnblogs.com/linuxchao/p/linuxchao-jenkins-setup.html,這裡需要注意一點儘量安裝
  • Appium+python自動化55-Unlock和Appium Setting
    注意:appium之前老的版本1.4和appium desktop v1.7以後版本安裝路徑不一樣,也有差異小編主要是以appium desktop(大於1.7版本)為例我的環境:appium desktop 桌面版本1.先看appium desktop桌面安裝版本,如下圖,我的版本是v1.7.12.雙擊安裝之後,會安裝到
  • appium自動化測試框架(PO)實戰
    最近連載2篇,小弟的appium文章,這是最後一篇,也是最乾貨、最有技術含量的一篇,因為結合了appium+po模型+unittest+公司的業務場景
  • 自動化-Appium-環境搭建-IOS(Python版)
    Appium Desktop官方下載地址:https://github.com/appium/appium-desktop/releases/11.1Appium Server例如:命令行安裝後的Appium-v1.8.0包.zip進行解壓,將解壓後的appium文件拷貝覆蓋到/usr/local/lib/node_modules/目錄下的appium文件。
  • Appium自動化(圖文教程).pdf
    一直以來小編忙於寫selenium的自動化教程,,appium的教程只出了前面的基礎入門系列。
  • 【app】自動化環境搭建(Appium)for java
    Appium來做app自動化相信大家都很熟悉了吧,就不再贅述他的概念和作用了,我們接下來著重介紹怎麼來搭建整個app自動化環境
  • Python appium搭建app自動化測試環境
    做app自動化測試,環境搭建是比較麻煩的。也是很多初學者在學習app自動化之時,花很多時間都難跨越的坎。但沒有成功的環境,就沒有辦法繼續後續的使用。 在app自動化測試當中,我們主要是通用電腦端的python代碼,能夠驅使手機端的app去進行操作。比如打開一個app,輸入用戶名和密碼,進入登陸操作。由於電腦端和手機端是兩個獨立的設備。
  • 以後做Appium自動化測試,再也不會踩這些坑了!
    E:\ProgramFiles(x86)\Python\Python37\lib\site-packages\selenium\webdriver\remote\webdriver.py:1031:UserWarning: name used for saved screenshot does not match file type.
  • Appium+Python做移動端自動化測試
    第一章 導言  1.1 編制目的  該文檔為選用Appium作為行動裝置原生(Native)、混合(Hybrid)、移動Web(Mobile Web)應用UI自動化測試的相關自動化測試人員、開發人員等提供參考。
  • java之appium自動化測試實踐!
    1、Appium設計理念webdriver 是基於 http 協議的,第一連接會建立一個 session 會話,並通過 post 發送一個 json 告知服務端相關測試信息客戶端通過 webdriver json wire 協議與伺服器通訊appium
  • RobotFramework +appium實現Android自動化
    1、已安裝python37版本(SDK、JDK均已安裝完成,且環境變量都配置好了)4、安裝appium(下載地址:http://6tt.co/pujb)5、安裝python測試庫-appium-python-client6、安裝python測試庫-robotframework-appiumlibrary下載成功:Appium-windows-1.17.1-1.exe(官網自行下載),