文章目錄
- 前言
- 一、頁面分析
- 二、撰寫爬蟲
- 1.引入庫
- 2.發出請求
- 2.1生成請求頭
- 2.2發出請求并獲取回應
- 3.決議回應的內容
- 4.保存提取的資訊到本地
- 5.康康主函式
- 三、運行結果
前言
使用python爬蟲爬取bilibli每日熱門視頻的資料
使用的第三方包有requests、my_fake_useragent
一、頁面分析
在進行爬蟲之前,我們先要對要爬取的頁面進行分析,找到想要使用的介面
bilibili熱門排行的地址:https://www.bilibili.com/v/popular/all?spm_id_from=333.851.b_7072696d61727950616765546162.3

如果我們直接進行http請求
import requests
url = 'https://www.bilibili.com/v/popular/all?' \
'spm_id_from=333.851.b_7072696d61727950616765546162.3'
response = requests.get(url)
print(response.text)
你會發現,回傳回來的html里面什么資訊都沒有,更別提去處理了

這是因為,這個頁面是使用動態html來進行生成的,你去請求這個url,只會回傳一個框架,里面的內容是由ajax&js動態生成的
所以,我們要捕獲對方用來動態生成頁面的介面,以此來請求資訊
————————————————————————————————————————
那么,怎么捕獲這個介面呢?
在這個頁面中,我們點擊F12進入開發者模式,選取network欄,過濾XHR(即ajax)

我們發現,每加載一批新的視頻,頁面都會呼叫一個介面

瞅一眼response

可以看到,所有視頻的資訊都在里面
所以,可以確定使用介面名叫做https://api.bilibili.com/x/web-interface/popular
ps和pn都是引數,ps是page_size代表每一頁的視頻個數,pn是page_num,帶表請求的頁數
為了確定介面的可用性,用瀏覽器請求一次試試

灰常成功,可以開心地寫程式了!
二、撰寫爬蟲
這個爬蟲的大概流程就是訪問對于每一頁發送一個請求,決議資料后保存到/popular/page_n檔案夾下
1.引入庫
import requests
import my_fake_useragent
import time
import json
import os
2.發出請求
2.1生成請求頭
def get_headers():
"""
生成回應頭
:return: 生成的回應頭
"""
# 隨機生成user_agent
user_agent = my_fake_useragent.UserAgent()
ua = str(user_agent.random())
headers = {
'user-agent': ua
}
return headers
2.2發出請求并獲取回應
def get_response(url, page=1, headers=get_headers()):
"""
請求該url并獲得回應
:param url: 要請求的url
:param page: 要請求的頁數
:param headers: 請求頭部
:return: 對于請求的回應
"""
# 請求的引數
params = {
'ps': '20',
'pn': str(page)
}
try:
# 發出請求
response = requests.get(url=url, params=params, headers=headers)
except Exception as e:
# 例外識別
return None
return response
3.決議回應的內容
剛付訓傳的回應特別亂,根本看不懂里面的元素是怎么排列的,所以先去json在線決議決議一下

可以看到,list里面存盤了所有的視頻物件(Object),我們只需要把它取出來再遍歷就行了
def parse_text(text=None):
"""
決議回應的文本
:param text:回應的文本
:return: 由資訊字典組成的串列[{info1}, {info2}, {info3}]
"""
# 將json檔案決議為字典
data = json.loads(text)
"""
data['data']是一個字典,包含若干資料
data['data']['list']是一個字典組成的list,包含每個視頻的資訊
"""
ret_list = []
temp_dict = {}
# 提取資料,生成回傳串列
for list_dict in data['data']['list']:
# 保存標題
temp_dict['title'] = list_dict['title']
# 保存封面圖片的地址
temp_dict['pic'] = list_dict['pic']
# 保存描述
temp_dict['desc'] = list_dict['desc']
# 保存投稿用戶id
temp_dict['name'] = list_dict['owner']['name']
# 保存觀看量
temp_dict['view'] = list_dict['stat']['view']
# 保存收藏數
temp_dict['favorite'] = list_dict['stat']['favorite']
# 保存投幣數
temp_dict['coin'] = list_dict['stat']['coin']
# 保存分享數
temp_dict['share'] = list_dict['stat']['share']
# 保存點贊數
temp_dict['like'] = list_dict['stat']['like']
# 保存BV號
temp_dict['bvid'] = list_dict['bvid']
# 將字典添加到回傳串列
ret_list.append(temp_dict.copy())
# 清空字典
temp_dict.clear()
return ret_list
4.保存提取的資訊到本地
ef save_infos(infos=None, page=1, main_path=None):
"""
保存資訊到指定的檔案夾
:param main_path: 主路徑
:param infos: 要保存的資訊
:param page: 要保存到的檔案夾序號
"""
# 讓編譯器識別一下串列,好把里面的方法識別出來,,,手懶
# infos = [].append(infos)
# 創建子檔案夾
dir_path = main_path + '/page%d' % page
if not os.path.exists(dir_path):
os.mkdir(dir_path)
# 遍歷讀取到的資訊
for info in infos:
# 以bv號命名檔案
file_path = dir_path + '/' +info['bvid'] + '.text'
# 打開檔案
with open(file_path, 'w', encoding='utf-8') as fp:
# 遍歷字典
for k, v in info.items():
fp.write('%s: %s' % (str(k), str(v)))
fp.write('\n')
5.康康主函式
def main():
# 需要請求的url
# 'https://api.bilibili.com/x/web-interface/popular?ps=20&pn=1'
url = 'https://api.bilibili.com/x/web-interface/popular'
# 創建主檔案夾
main_path = url.split('/')[-1]
if not os.path.exists(main_path):
os.mkdir(main_path)
# 設定起始頁碼
page_start = int(input('start: '))
page_end = int(input('end: '))
# page_start = 1
# page_end = 1
# 主回圈開始
# 主回圈開始
for i in range(page_end - page_start + 1):
page_num = i + 1
# 請求頁面并獲得回應
print('第%d頁開始下載……' % page_num)
response = get_response(url=url, page=page_num, headers=get_headers())
# 判斷請求是否成功
if not(response is None) and response.status_code == 200:
# 請求成功
# 獲取并決議回應的內容
text = response.text
infos = parse_text(text)
save_infos(infos=infos, page=page_num, main_path=main_path)
print('第%d頁下載完成' % page_num)
else:
# 請求失敗
print('!!第%d頁請求失敗!!' % page_num)
continue
# 文明爬蟲!!!
time.sleep(3)
if __name__ == '__main__':
print('開始')
start_time = time.time()
main()
end_time = time.time()
print('完成<%f>' % (end_time - start_time))
三、運行結果


轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/248602.html
標籤:python
