前言
說起APP爬蟲,相信大家會很容易聯想到一些抓包工具:Fiddler、Charles、mitmproxy和anyproxy等等。
借助這些抓包工具,我們可以知道APP在運行過程中具體發起了什么請求,之后我們就可以詳細分析這些請求,再用程序模擬這些請求最終實現爬蟲。
然而,在爬蟲的實操中,APP的各種反爬措施也是不容小覷的,比如抓包失敗、參數加密、代碼被編譯等等,都增加了我們爬取APP數據的難度。
那么作為一名不懂抓包的小白,是不是就無緣爬蟲了呢?不要慌,今天我們就帶大家 用airtest來實現1個模擬抓取的過程 ,把網易雲音樂中抖音排行榜的100首歌曲名稱爬取下來!
准備工作
為了 爬取抖音排行榜100首歌曲的名稱 ,首先我們需要編寫1個自動化腳本,在APP內打開這個排行榜,步驟如下:
- 1.連接測試設備
- 2.打開網易雲音樂的APP
- 3.初始化poco
- 4.同意首頁的服務條款彈窗
- 5.勾選用戶協議並點擊立即體驗
- 6.點擊輸入按鈕並輸入“抖音”
- 7.點擊搜索關鍵詞並等待排行榜加載
- 8.點擊進入抖音排行榜
代碼實現如下:
# -*- encoding=utf8 -*- __author__ = "AirtestProject" from airtest.core.api import * auto_setup(__file__,devices=["Android://127.0.0.1:5037/emulator-5554"]) clear_app("com.netease.cloudmusic") start_app("com.netease.cloudmusic") sleep(1.0) from poco.drivers.android.uiautomation import AndroidUiautomationPoco poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False) # 同意服務條款 poco("com.netease.cloudmusic:id/agree").click() wait(Template(r"tpl1595916981414.png", record_pos=(0.004, -0.452), resolution=(900, 1600))) sleep(2.0) # 勾選用戶協議並點擊立即體驗 poco("com.netease.cloudmusic:id/agreeCheckbox").click() poco("com.netease.cloudmusic:id/trial").click() sleep(2.0) poco("搜索").wait_for_appearance() sleep(1.0) # 點擊搜索按鈕並輸入“抖音” poco("搜索").click() sleep(1.0) poco("com.netease.cloudmusic:id/search_src_text").click() poco("com.netease.cloudmusic:id/search_src_text").set_text("抖音") sleep(1.0) poco.click([0.14,0.13]) assert_exists(Template(r"tpl1595821867472.png", record_pos=(-0.283, -0.489), resolution=(900, 1600)), "找到抖音排行榜") # 點擊進入抖音排行榜 poco("com.netease.cloudmusic:id/title").click()
其中需要注意的是poco的初始化順序,先連接設備,再打開APP,最后才初始化poco,可以有效避免一些奇奇怪怪的錯誤。
爬取歌名
進入抖音排行榜的歌曲列表之后,我們先來觀察下此刻的UI樹結構:
從UI樹中我們可以知道,歌曲名稱這個控件,都在 musicListItemContainer
這個控件里面,所以為了獲取歌曲名稱,首先我們需要遍歷所有加載出來的 musicListItemContainer
,再定位到歌曲名稱的控件,依此來獲取控件的 text
屬性:
for title in poco("com.netease.cloudmusic:id/musicInfoList").child("com.netease.cloudmusic:id/musicListItemContainer"): a = title.offspring("com.netease.cloudmusic:id/songName") name = a.get_text() print(a)
獲取完當前頁面加載的所有歌曲名稱之后,我們可以通過向上滑動列表,來不斷加載新的歌曲控件。
但這時候,我們還需要解決2個問題:
① 我們單次向上滑動歌曲列表,並不能保證當前加載出來的歌曲控件都是新的控件,有可能某些控件里面的歌曲名稱我們已經獲取到了,那么 如何解決獲取歌名重復的問題呢 ?
我們可以事先定義好1個空的數組,將獲取到的歌曲名稱放到數組里面,在放入歌曲名稱之前,做1個判斷,放入數組的歌名不能與數組已經存在的歌名相同,這樣子就能夠保證我們每次放入的都是新的歌名;
② 多次滑動列表之后,我們 如何判斷所有歌曲名稱已經獲取完畢呢 ?很簡單,我們可以設置1個數組長度的計數器,當數組長度不再增加,即沒有新的名字被添加到數組的時候,既可以認為我們已經把排行榜的歌曲名稱獲取完了。
最終實現的效果如下:
# 定義1個空數組用於存放排行榜的歌名 titles = [] # 定義數組目前的長度和最終的長度 current_count, last_count = len(titles), len(titles) while True: last_count = len(titles) for title in poco("com.netease.cloudmusic:id/musicInfoList").child("com.netease.cloudmusic:id/musicListItemContainer"): a = title.offspring("com.netease.cloudmusic:id/songName") if not a.exists(): continue name = a.get_text() if not name in titles: titles.append(name) print(name) current_count = len(titles) poco.swipe([0.5,0.7],[0.5,0.1],duration=2) sleep(1.0) # 當倆者數值相等,即current_count不再增加時,表明爬取完畢 if current_count == last_count: print("總共爬取"+str(last_count)+"首歌曲的名稱") break
小結
上述就是利用airtest實現模擬爬取的全部過程。當然,我們不僅可以把爬取的歌曲名稱打印在log查看窗中,還可以將它保存在指定的文檔中,這個大家可以嘗試着自己實現一下。
Airtest官網:http://airtest.netease.com/
Airtest教程官網:https://airtest.doc.io.netease.com/
搭建企業私有雲服務:https://airlab.163.com/b2b