最近無聊分析了一下b站的視頻流協議,簡單分享下爬取的流程。
首先先要找到視頻對應的aid和cid,aid就相當於av號,而av號對應網頁下的每一個視頻都有對應的cid,普通視頻就是分p,番劇就是集數,aid和cid在網頁的源代碼里面都能找到,用正則匹配aid和cid這兩個關鍵字就能匹配到,如下代碼:
1 url = '' #這里是需要下載的視頻網址 2 html = requests.get(url,headers).text 3 aid = json.loads(re.findall(r'"aid":(\d+)',html)[0]) #這里是aid 4 pages = json.loads(re.findall(r'"pages":(\[.+?\])',html)[0]) 5 cidlist = [] #這里是cid的列表 6 for i in pages: 7 cidlist.append(i['cid'])
b站視頻流地址api如下:
https://api.bilibili.com/pgc/player/web/playurl?fnval=80&cid={c} (這是番劇的)
https://api.bilibili.com/x/player/playurl?fnval=80&avid={a}&cid={c} (這是視頻的)
如上api會返回json字符串,包含各種支持的編碼和分辨率的視頻流,番劇只需要cid就能訪問所以可以不提取aid,有些番劇和分辨率可能得大會員或者港澳台才能使用,如有需要請修改請求的cookie和ip地址。
其中關於video的json字符串如下:
"video": [
{ "start_with_sap": 1, "bandwidth": 4112579, "sar": "1:1", "backupUrl": [""], "codecs": "avc1.640028", "base_url": "", "backup_url": [""], "segment_base": { "initialization": "0-990", "index_range": "991-4490" }, "mimeType": "video/mp4", "frame_rate": "16000/672", "SegmentBase": { "Initialization": "0-990", "indexRange": "991-4490" }, "frameRate": "16000/672", "codecid": 7, "baseUrl": "", "size": 0, "mime_type": "video/mp4", "width": 1920, "startWithSAP": 1, "id": 112, "height": 1080, "md5": "" }]
其中的base_url、id和codecs字段是我們需要的。不同的id對應不同的分辨率,codecs對應編碼方式,base_url就是對應分辨率和編碼方式下的視頻流地址。
audio對應的json字符串和video類似,同樣是base_url為音頻流地址。
(注意其上的api都得在請求頭加referer字段,否則無法訪問)
視頻流地址可以在請求頭加range字段,用於分段下載或者部分下載,如不加則為下載所有,代碼如下:
headers = { 'user-agent':'', 'referer':'', 'range':'byte=0-9999' #此為range字段,代表下載整個視頻從0到9999字節的數據 } with open('demo_vedio.mp4','wb+') as file1, open('demo_audio.mp3','wb+') as file2:
file1.write(requests.get(vedio_url,headers=headers).content) #下載video
file2.write(requests.get(audio_url,headers=headers).content) #下載audio
接下來就是等資源下載完畢了,如有需要可以用格式工廠將音頻視頻合並成為一個完整的視頻。
總結:b站還是很友好的,沒有弄一些加密什么的來防爬,通過這次也大致了解了hash協議的原理,總體來說想下載b站視頻並不難。
b站視頻下載相關的源碼網址:https://github.com/modifyGB/bili_video_download