《工作細胞》最近比較火,bilibili 上目前的短評已經有17000多條。 先看分析下頁面 右邊 li 標簽中的就是短評信息,一共20條。一般我們載入大量數據的時候,都會做分頁,但是這個頁面沒有,只有一個滾動條。 隨著滾動條往下拉,信息自動載入了,如下圖,變40條了。由此可見,短評是通過非同步載入的 ...
《工作細胞》最近比較火,bilibili 上目前的短評已經有17000多條。
先看分析下頁面
右邊 li 標簽中的就是短評信息,一共20條。一般我們載入大量數據的時候,都會做分頁,但是這個頁面沒有,只有一個滾動條。
隨著滾動條往下拉,信息自動載入了,如下圖,變40條了。由此可見,短評是通過非同步載入的。
我們不可能一次性將滾動條拉到最下麵,然後來一次性獲取全部的數據。既然知道是通過非同步來載入的數據,那麼我們可以想辦法直接去獲取這些非同步的數據。
打開 Network 查看分析 http 請求,可以點擊 XHR 過濾掉 img、css、js 等信息。這時我們發現了一些 fetch。fetch 我對它的瞭解就是一個比 ajax 更高級更好用的 API,當然這肯定是不准確的,但並並不影響我們的爬蟲。
我們可以看到,其中返回的就是我們需要的內容,json 格式,一共20條,total 屬性就是總的數目。分析一下 url 地址:https://bangumi.bilibili.com/review/web_api/short/list?media_id=102392&folded=0&page_size=20&sort=0&cursor=76729594906127
media_id 想必就是《工作細胞》的 id 了;
folded 不知道是啥,可以不管;
page_size 是每頁的條數;
sort 排序,看名字就知道,找到排序的選項,試了下,果然是的,預設0,最新1;
cursor,字面意思的游標,猜測應該是指示本次獲取開始的位置的,展開獲取到的 json,發現其中包含有 cursor 屬性,對比以後可以發現,url中的值跟上一次返回結果中的最後一條中的 cursor 的值是一致的。
好了,至此,頁面已經分析清楚了,爬取的方式也明顯了,根本不用管網頁,直接根據 fetch 的地址獲取 json 數據就可以了,連網頁解析都省了,超級的方便。
下麵的完整的代碼:(如果 fake_useragent 報錯,就手動寫個 User-Agent 吧,那個庫極度的不穩定)
import csv
import os
import time
import requests
from fake_useragent import UserAgent
curcount = 0
def main():
url = 'https://bangumi.bilibili.com/review/web_api/short/list?media_id=102392&folded=0&page_size=20&sort=0'
crawling(url)
def crawling(url):
print(f'正在爬取:{url}')
global curcount
headers = {"User-Agent": UserAgent(verify_ssl=False).random}
json_content = requests.get(url, headers).json()
total = json_content['result']['total']
infolist = []
for item in json_content['result']['list']:
info = {
'author': item['author']['uname'],
'content': item['content'],
'ctime': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(item['ctime'])),
'likes': item['likes'],
'disliked': item['disliked'],
'score': item['user_rating']['score']
}
infolist.append(info)
savefile(infolist)
curcount += len(infolist)
print(f'當前進度{curcount}/{total}')
if curcount >= total:
print('爬取完畢。')
return
nexturl = f'https://bangumi.bilibili.com/review/web_api/short/list?' \
f'media_id=102392&folded=0&page_size=20&sort=0&cursor={json_content["result"]["list"][-1]["cursor"]}'
time.sleep(1)
crawling(nexturl)
def savefile(infos):
with open('WorkingCell.csv', 'a', encoding='utf-8') as sw:
fieldnames = ['author', 'content', 'ctime', 'likes', 'disliked', 'score']
writer = csv.DictWriter(sw, fieldnames=fieldnames)
writer.writerows(infos)
if __name__ == '__main__':
if os.path.exists('WorkingCell.csv'):
os.remove('WorkingCell.csv')
main()