首頁 > 軟體

Python 爬蟲:獲取 JS 動態內容——應用寶搜尋應用!

2021-05-29 10:00:18

1.1 Ajax 非同步載入生成網頁內容

現在越來越多的網頁使用 Ajax 非同步載入方式,即網頁中的一些內容由前端的 JS 動態生成。由於呈現在網頁上的內容是由 JS 生成而來,我們能夠在瀏覽器上看到,但是在 HTML 源碼中卻發現不了。

比如應用寶的搜尋應用頁面,顯示如下:

從上面可以看到,搜尋出來的應用列表資訊是在 id="J_SearchDefaultListBox" DOM 樹下面。

檢視當前網頁的源碼(使用快捷鍵 「Ctrl + U」)如下:

在源碼中,發現元素 id="J_SearchDefaultListBox" 下面的內容為空,沒有任何應用列表資訊。

通過上面的分析可知,應用寶應用搜索頁面中顯示的應用列表是由 JS 動態生成載入的。

遇到這種情況,我們應該如何對網頁內容進行爬取呢?一般有兩種方法:

(1)從網頁響應中找到 JS 指令碼返回的資料(大多是 json 格式,也有 xml 格式。);

(2)使用 Selenium 對網頁進行模擬訪問。

下面我們將介紹第一種方法。第二種方法可以參考這裡。

1.2 從網頁響應中找到 JS 指令碼返回的資料 既然網頁內容是由 JS 動態生成載入的,那麼 JS 就需要先對某個介面進行呼叫,然後根據介面返回的資料再進行載入和渲染。那我們可以先找到 JS 呼叫的資料介面,從資料介面中找到網頁中最後呈現的資料。 下面我們就以應用寶的搜尋應用頁面為例,進行說明。

1.2.1 找到 JS 請求的資料介面

按照如下步驟進行操作:

開啟應用寶的搜尋頁面(https://android.myapp.com/myapp/search.htm)按 F12 開啟網頁偵錯工具選擇 「Network」 選項卡選擇 「XHR」(即 XMLHTTPRequest,是 Ajax(Asynchronous JavaScript and XML,非同步的 JavaScript 和 XML) 中的概念。 )輸入應用名(例如:微信)將看到如下資訊:

在這裡,我們看到只有一個 request(其他網頁可能會存在多個)。點選這個 request,然後選擇 「Preview」,可以看到如下資料:

在上面的資料中,我們發現了「微信」、「多開助手」等資訊,這些就是搜尋出來的應用列表資訊。

通過上面的分析,可以知道搜尋出來的應用列表資訊正是通過這個 request 獲取的。這個 request 對應 URL 為 https://android.myapp.com/myapp/searchAjax.htm?kw=%E5%BE%AE%E4%BF%A1&pns=&sid=(獲取方法:將滑鼠移動到這個 request 上 -> 然後右鍵單擊 -> Copy -> Copy link address)。

將上面的 URL 在瀏覽器中開啟,會返回一串資料。看起來似乎很亂,但實際上是 JSON 格式的資料。

這樣,我們就找到了 JS 請求的資料介面。

1.2.2 URL 編碼 上面我們找到的 JS 請求的資料介面是 https://android.myapp.com/myapp/searchAjax.htm?kw=%E5%BE%AE%E4%BF%A1&pns=&sid=,但是其中的 %E5%BE%AE%E4%BF%A1 代表什麼意思呢?

實際上 %E5%BE%AE%E4%BF%A1 是中文 微信 的 URL 編碼。在 Python 中,可以使用 urllib.parse.quote() 得到,即 '%E5%BE%AE%E4%BF%A1' = urllib.parse.quote('微信')。

按照標準,URL 中只允許包含英文字母、數字以及部分符號,其他字元(比如中文)是不符合 URL 標準的。這個時候就需要進行 URL 編碼。

1.2.3 程式碼實現

按照以下 4 步進行實現:

(1)引入相關的庫;

(2)對 JS 請求的資料介面進行請求;

(3)對 HTTP 響應的資料進行 json 格式化;

(4)進行遍歷獲取列表中 App 的資訊(App 名稱、包名、版本號、apk 下載 URL等)

import jsonimport requestsfrom urllib.parse import quote# 對資料介面進行 http 請求app_name = '微信'url = 'https://android.myapp.com/myapp/searchAjax.htm?kw={}&pns=&sid=' .format(quote(app_name))web_data = requests.get(url).text# 對 http 響應的資料進行 json 格式化data = json.loads(web_data)app_infos = data['obj']['appDetails']# 進行遍歷獲取列表中 App 的資訊(App 名稱、包名、版本號、apk 下載 URL等)for app_info in app_infos: app_name = app_info['appName'] pkg_name = app_info['pkgName'] version_code = app_info['versionCode'] version_name = app_info['versionName'] download_url = app_info['apkUrl'] print(app_name, pkg_name, version_code, version_name, download_url)

近期有很多朋友通過私信諮詢有關Python學習問題。為便於交流,點選藍色自己加入討論解答資源基地


IT145.com E-mail:sddin#qq.com