1. 程式人生 > >python爬蟲爬取非同步載入網頁資訊(python抓取網頁中無法通過網頁標籤屬性抓取的內容)

python爬蟲爬取非同步載入網頁資訊(python抓取網頁中無法通過網頁標籤屬性抓取的內容)

1.問題描述

最近由於學習內容的要求,需要從網頁上抓取一些資料來做分析報告,在看了python爬蟲的一些基礎知識之後就直接上手去網站上爬資料了。作為新手踩坑是無法避免,最近就遇到了一個比較難的問題:
一般情況下,要抓去網頁上某個標籤上的內容,在通過urllib下載網頁內容後通過BeautifulSoup物件解析網頁內容,然後就可以通過fina_all()方法找到我們想要的標籤內容。
舉個例子,我想抓取QQ音樂分類歌單下的所有歌單資訊,將任務分解後應該是:

  1. 抓取當前頁面的歌單資訊;
  2. 翻頁;
  3. 判斷是否是最後一頁,若不是最後一頁回到第1步,若是最後一頁,結束爬蟲程式。

首先寫一個簡單的抓取單頁面所有歌單的標題的程式碼:

import urllib
from bs4 import BeautifulSoup

url = https://y.qq.com/portal/playlist.html
html = urllib.urlopen(url)
bsObj = BeautifulSoup(html)
playTitle_list = bsObj.find_all("span", {"class": "playlist__title_txt"})	# 抓取該頁面歌單標題並儲存在列表中
print(playTitle_list)
for playTitle in playTitle_list:	# 輸出所有標題
	print(i.get_text())

標籤引數通過右擊網頁檢查網頁屬性可以找到歌單標題資訊通過屬性class 取值為 playlist_title_txt 的span標籤展示,但是在執行程式碼後輸出結果只有一個空列表,很奇怪是不是?作為一個新手我是真的是花了好長時間絞盡腦汁都想不出原因。

之後和同學交流聽他聊到他之前看到的非同步載入內容,發現和我抓取的網頁特徵有點像,就特地去了解了一下

通俗的描述一下就是這個非同步載入的網頁所展示的內容並全是來自當前的網址所代表的網頁檔案,其中有一部分內容是當前的網頁檔案通過函式呼叫另一個網頁的內容載入過來的,也就是說要抓取的內容所屬的網頁檔案和當前網頁檔案確實不是同一個檔案,所以抓取不到。因此需要找到抓取的內容真正所屬的檔案。

2.解決方案

接下介紹如何尋找非同步載入的檔案以及抓取過程中可能會遇到的坑
1.右擊網頁選擇**“檢查”,在除錯介面中找到“網路”(network)選項,然後逐個找js檔案(記得重新整理網頁不然js檔案不會顯示出來),通過preview**來檢視內容是不是自己想爬去的內容
在這裡插入圖片描述

2.在每個js檔案的具體資訊面板中可以通過preview來檢視傳遞過來的內容,我們找到了歌單標題資訊的原始檔,然後通過Headers屬性可以找到給資訊真正的原始檔的連結,並將url作為我們的requests引數。
在這裡插入圖片描述

在Headers屬性下的general 和request headers包括了我們要的資訊,其中url在general屬性下,同時也包括了傳值型別,這裡的是get。
因此我們可以通過request模組獲取歌單資訊。這裡需要注意的是:要把網頁的request headers值傳遞給requests模組的get方法,不然無法獲取網頁

import requests
url = ...
headers ={...} # headers資訊要以字典的形式儲存
jsContent = requests.get(url).text

3.以上處理過程一般情況下獲得的是json物件(看起來是字典的字串表現形式),在python中可以直接使用json模組,將json物件轉換成python物件—字典,以方便通過key來獲取資料

jsDict = json.loads(jsContent)

但是有時候獲取的資料形式會在json物件外加上json物件名稱,比如:

playList({...}) # 其中{}表示json物件內容

這樣的話就無法通過 json模組轉換資料型別,一般會出現異常

json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

這個異常情況可以通過字串的切片把json物件資訊截取出來,之後就可以通過json模組轉換資料型別了(這是我想出的一個比較笨方法,如果有大佬知道比較正規的方法,希望指正一下 (っ•̀ω•́)っ✎⁾⁾ )