python爬蟲之Appium爬取手機App數據及模擬用戶手勢
Appium
在前文的講解中,我們學會瞭如何安裝Appium,以及一些基礎獲取App元素內容的方式。但認真看過前文的讀者,肯定在博主獲取元素的時候觀察到瞭一個現象。
那就是手機App的內容並不是一次性加載出來的,比如大多數Android手機列表ListView,都是異步加載,也就是你滑動到那個位置,它才會顯示出它的內容。
也就是說,我們前面爬取微博首頁全部信息的時候,如果你不滑動先加載一定的微博內容,也就如上圖所示,隻能獲取2個微博內容。
模擬操作
所以,我們要實戰獲取微博內容的話,首先你需要學會如何模擬滑動屏幕操作。下面,我們來一一介紹屏幕的互動操作。
屏幕滑動
在Python的Appium-Python-Client包中,我們通過swipe()函數模擬用戶手勢從A滑動到B點,其具體的方法定義如下所示:
def swipe(self: T, start_x: int, start_y: int, end_x: int, end_y: int, duration: int = 0) -> T
start_x:開始位置的橫坐標
start_y:開始位置的縱坐標
end_x:結束位置的橫坐標
end_y:結束位置的縱坐標
duration:持續時間,也就是處於距離後生成滑動速度
當然,滑動的方法還有一個:flick(),它隻有4個參數,缺少duration參數,也就是快速從某個位置滑動到指定的位置。
示例代碼:
from appium import webdriver import time server = "http://localhost:4723/wd/hub" desired_caps = { "platformName": "Android", "deviceName": "liyuanjing", "appPackage": "com.sina.weibo", "appActivity": "com.sina.weibo.MainTabActivity", } driver = webdriver.Remote(server, desired_caps) time.sleep(5) el1 = driver.find_element_by_id("com.android.permissioncontroller:id/permission_allow_button") el1.click() time.sleep(5) driver.swipe(500,500,500,2000,3000)
上面代碼實現的下拉屏幕刷新功能,下拉刷新其實也是一個滑動的操作,是先滑動一段距離然後松開。
當然,如果你要實現上滑加載更多的微博,可以直接將坐標顛倒過來即可,這裡我們將方法替換成flick(),也就是隻需要替換最後一行代碼。
driver.flick(487, 2085, 513, 257)
不過,這裡有一個非常顯著的問題,手機的坐標到底寬高都是多少呢?雖然說,我們程序員什麼都通過代碼先解決不要一上來就用工具。
但博主想說,這種坐標每個手機的像素分辨率都不同,比如上面swipe就是博主猜測的坐標。而flick()博主試瞭半天,沒弄出來,最後還是借助Appium生成坐標給我。
如上圖所示,我們先點擊藍色選框中像“一橫”的圖標,然後記得點錄制“眼睛”按鈕。接著,在App上拉兩個點,這2個點就是滑動的間距,最後生成如下圖所示的代碼。
這裡就有2個坐標,當然上面的代碼是動作鏈的知識後面我們會講解。這裡我們需要copy這2個坐標到flick()方法中,然後就可以下滑微博加載數據。
至於加載微博的動圖與下滑微博的動圖,大傢都玩過微博,這裡不需要演示。
屏幕點擊
以前的微博都是限制為140字,你不需要打開微博詳情,也能看到微博的所有數據。但是自從長微博出現之後,有些微博還必須點擊進去才能看完整。
同樣,我們爬取這些數據,有時候也要點擊進去才能完全獲取長微博的數據。所以,我們需要掌握如何點擊某個微博。
在Appium包中,我們點擊微博使用的是:tap()方法。該方法不僅支持單指點擊,而且最多可以支持5個手指,同時也可以設置點擊的時長。具體定義如下:
def tap(self: T, positions: List[Tuple[int, int]], duration: Optional[int] = None) -> T
positions:點擊的位置組成的列表,比如五個手指,那就是5個坐標值的列表
duration:點擊持續的時間,時間短就是點擊操作,時間長就是長按操作
示例代碼如下:
el2 = driver.tap([(500,500)]) el2.click()
不過,這裡有讀者肯定會問,每條微博的我難道用坐標取定位?那是怎麼區分你點的是哪條微博,畢竟一個頁面最少也有2條微博。這裡,我們先來看張圖:
這裡,博主點擊的是第2條微博數據,可以看到其id就是微博的內容。所以,後面我們想要獲取微博的詳細內容,可以直接通過獲取內容後在點擊。
屏幕拖動
看到這個小標題,博主都有寫困惑。拖動與滑動是不是差不多的?
還別說,博主覺得還真差不多,不過這2個在Appium包中的方法卻不一樣,前文的滑動時通過坐標進行定位的,這裡的拖動是通過元素定位的。
比如,你需要你滑動的距離是一個按鈕到另一個按鈕的位置,我們可以直接獲取到這2個按鈕,然後使用scroll()方法實現滑動操作。其定義如下:
def scroll(self: T, origin_el: WebElement, destination_el: WebElement, duration: Optional[int] = None) -> T
origin_el:被操作的元素
destination_el:目標元素
duration:持續時間
這裡就不演示瞭,就是獲取元素位置然後拖動到指定元素的位置。與前文實現的效果差不多,隻是將坐標變成瞭2個元素的位置。
屏幕拖拽
同樣的,微博不好演示的還有拖拽操作。它的方法為drag_and_drop(),其定義如下:
def drag_and_drop(self: T, origin_el: WebElement, destination_el: WebElement) -> T
origin_el:被拖拽的元素
destination_el:目標元素
這裡的拖拽你可以理解為將一個按鈕元素拖動到另一個按鈕的位置,這裡拖拽的是元素本身,不是位置的滑動。微博中暫時也沒有演示的操作,感興趣的可以測試其他App。
文本輸入
在模擬登錄或者說這裡發微博的時候,用戶肯定需要模擬輸入文本。而且,在需要登錄的爬蟲場景之下,登錄都是必備步驟。比如微信朋友圈內容的爬取,你不登陸看得到朋友圈嗎?
所以,我們需要掌握Appium的文本輸入操作。而它提供瞭2個方法進行文本的輸入,一個是set_text();一個是send_keys()。
現在我們模擬微博輸入賬號,示例代碼如下:
from appium import webdriver import time from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as ec server = "http://localhost:4723/wd/hub" desired_caps = { "platformName": "Android", "deviceName": "liyuanjing", "appPackage": "com.sina.weibo", "appActivity": "com.sina.weibo.MainTabActivity", } driver = webdriver.Remote(server, desired_caps) wait = WebDriverWait(driver, 20) time.sleep(5) el1 = driver.find_element_by_id("com.android.permissioncontroller:id/permission_allow_button") el1.click() el2 = wait.until(ec.presence_of_element_located((By.ID, 'com.sina.weibo:id/titleBack'))) el2.click() el3 = wait.until(ec.presence_of_element_located((By.ID, 'com.sina.weibo:id/et_login_view_phone'))) el3.send_keys("[email protected]")
這裡,我們隻是模擬輸入文本,當然登錄用戶名是手機,但手機屬於隱私。博主這裡替換成郵箱。感興趣的可以自己替換手機試試。同時也可以替換為send_text()方法。
動作鏈
動作鏈顧名思義就是一系列操作動作的組合。在Selenium中,動作鏈是ActionChains,而Appium中,動作鏈是TouchAction。
比如,我們執行的下拉刷新其實就是一個動作鏈。這裡,我們會執行2個動作,一個是按壓,一個是從指定位置滑動到另一個位置。這裡,我們將2個動作組合實現:
TouchAction(driver).press(x=380, y=2101).move_to(x=390, y=519).release()
實戰:爬取微博首頁信息
其實,Appium開始推出的時候,是為瞭自動化測試準備的工具,並不專用於爬蟲數據。而且Appium有一個缺陷,目前沒有直接的辦法獲取圖片。
如果你想下載App界面中的圖片,可以模擬用戶長按的操作進行圖片的下載。也可以直接截圖。話不多說,我們來實現獲取微博的文字信息並保存到目錄。示例如下:
from appium import webdriver import time from selenium.webdriver.support.ui import WebDriverWait import os def mkdir(path): path = path.strip() path = path.rstrip("\\") isExists = os.path.exists(path) # 判斷結果 if not isExists: # 如果不存在則創建目錄 # 創建目錄操作函數 os.makedirs(path) print(path + ' 創建成功') return True else: # 如果目錄存在則不創建,並提示目錄已存在 print(path + ' 目錄已存在') return False server = "http://localhost:4723/wd/hub" desired_caps = { "platformName": "Android", "deviceName": "liyuanjing", "appPackage": "com.sina.weibo", "appActivity": "com.sina.weibo.MainTabActivity", } driver = webdriver.Remote(server, desired_caps) wait = WebDriverWait(driver, 20) time.sleep(5) el1 = driver.find_element_by_id("com.android.permissioncontroller:id/permission_allow_button") el1.click() time.sleep(5) mkdir("weiboFile") for i in range(10): items = driver.find_elements_by_id("com.sina.weibo:id/contentTextView") for item in items: txt_text = item.get_attribute("content-desc") folder_output = 'weiboFile/%s.txt' % str(int(time.time())) with open(folder_output, "w", encoding='utf-8') as f: f.write(txt_text) f.close() print(txt_text) driver.swipe(487, 2085, 513, 257, 3000)
上面代碼主要的功能在for-in循環之中。這裡,我們通過先獲取文本數據保存之後,在滑動屏幕獲取其他的微博數據。
如果你想獲取更多的數據,可以把循環的次數設置的更大一些。因為App的數據都是在滑動之中進行加載的。運行之後,效果如下所示:
到此這篇關於python爬蟲之Appium爬取手機App數據及模擬用戶手勢的文章就介紹到這瞭,更多相關Appium爬取手機App數據內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Python利用appium實現模擬手機滑動操控的操作
- 基於python實現微信收紅包自動化測試腳本(測試用例)
- 詳解appium自動化測試工具(monitor、uiautomatorviewer)
- python利用Appium實現自動控制移動設備並提取數據功能
- python開發App基礎操作API使用示例過程