您好,登錄后才能下訂單哦!
這篇文章主要介紹了Python如何爬取到B站的彈幕,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
本文的文字及圖片來源于網絡,僅供學習、交流使用,不具有任何商業用途,如有問題請及時聯系我們以作處理。
想必小破站大家都很熟悉叭,里面充滿了各種神奇的視頻,其中的「彈幕」成為了許多人的快樂源泉。關于它的爬蟲也有很多,但大部分都受限于彈幕池的數量,只能爬取到其中很少一部分的彈幕。
那么,有沒有辦法可以爬取到B站更多的彈幕呢?
首先,我們需要找到B站視頻彈幕的接口,通過瀏覽器的F12調試工具抓包可以發現,其接口為:
https://api.bilibili.com/x/v1/dm/list.so?oid={oid/cid}
其實,除了這個接口之外,還有另外一個接口同樣是可以獲取到彈幕的:
https://comment.bilibili.com/{oid/cid}.xml
其中「oid」和「cid」是iB站給每個視頻分配的一個id號,但是通常我們在瀏覽器地址看到的是「bvid」,因此需要做個轉換:
這里相關的接口有很多,可以定義如下函數:
def get_cid(bvid): ''' 通過視頻的bvid獲得視頻的cid 輸入:視頻的bvid 輸出:視頻的cid ''' url = 'https://api.bilibili.com/x/player/pagelist?bvid=%s&jsonp=jsonp'%bvid res = requests.get(url) data = res.json() return data['data'][0]['cid']
有了「cid」之后,我們便可以通過剛才發現的彈幕接口爬取彈幕了,代碼如下:
oid = get_cid(bvid) # 這里的cid和oid是一樣的 url = 'https://api.bilibili.com/x/v1/dm/list.so?oid=%d'%oid res = requests.get(url) res.encoding = 'utf-8' text = res.text
注意:這里需要指定res的編碼方式為utf-8,否則會出現亂碼現象。
我們得到的請求為一個xml文件,其格式大致如下:
那么,利用正則可以它們都提前出來:
def parse_dm(text): ''' 解析視頻彈幕 輸入:視頻彈幕的原數據 輸出:彈幕的解析結果 ''' result = [] # 用于存儲解析結果 data = re.findall('<d p="(.*?)">(.*?)</d>',text) for d in data: item = {} # 每條彈幕數據 dm = d[0].split(',') # 彈幕的相關詳細,如出現時間,用戶等 item['出現時間'] = float(dm[0]) item['模式'] = int(dm[1]) item['字號'] = int(dm[2]) item['顏色'] = int(dm[3]) item['評論時間'] = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(int(dm[4]))) item['彈幕池'] = int(dm[5]) item['用戶ID'] = dm[6] # 并非真實用戶ID,而是CRC32檢驗后的十六進制結果 item['rowID'] = dm[7] # 彈幕在數據庫中的ID,用于“歷史彈幕”功能 item['彈幕內容'] = d[1] result.append(item) return result
通過解析requests的請求,便能得到相應的彈幕:
dms = parse_dm(text) # 解析彈幕
但是,這里受到彈幕池的限制,每次只能抓取一小部分,當彈幕數量很多時,顯然這個辦法行不通。
那么,我們得另尋它路了~
通過分析,我們可以找到另外一個接口,用于獲取每天的彈幕歷史數據:
https://api.bilibili.com/x/v2/dm/history?type=1&oid={oid/cid}&date=xx-xx
「date」為日期,通過遍歷日期便可獲得更多的彈幕。需要注意的是,這個接口需要登陸,因此在請求的時候必須得加入cookies,可以定義如下函數:
def get_history(bvid,date): ''' 獲取視頻歷史彈幕 輸入:視頻bvid,日期 輸出:視頻某一日期開始的彈幕 ''' oid = get_cid(bvid) url = 'https://api.bilibili.com/x/v2/dm/history?type=1&oid=%d&date=%s'%(oid,date) headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0', 'Accept': '*/*', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'Origin': 'https://www.bilibili.com', 'Connection': 'keep-alive', 'Referer': 'https://www.bilibili.com/video/BV1k54y1U79J', 'TE': 'Trailers'} # 此接口需要登陸,因此需要cookies cookies = {} res = requests.get(url,headers=headers,cookies=cookies) res.encoding = 'utf-8' text = res.text dms = parse_dm(text) # 解析彈幕 return dms
想要獲得更多的彈幕,遍歷每一天的彈幕數據即可,但是這樣存在兩個問題:「效率太低」、「數據重復」。因為,每次獲取通常可以得到跨越幾天的數據,所以我們無需每天都去訪問,而是根據結果逐步往前推即可:
def get_dms(bvid): ''' 獲取視頻彈幕(此方法獲取的彈幕數量更多) 輸入:視頻的bvid 輸出:視頻的彈幕 ''' print('視頻解析中...') info = get_info(bvid) print('視頻解析完成!') print('【視頻標題】: %s\n【視頻播放量】:%d\n【彈幕數量】: %d\n【上傳日期】: %s'%(info[0],info[1],info[2],info[3])) dms = get_dm(bvid) # 存儲彈幕 if len(dms) >= info[2]: # 如果彈幕數量已抓滿 return dms else: dms = [] date = time.strftime('%Y-%m-%d',time.localtime(time.time())) # 從今天開始 while True: dm = get_history(bvid,date) dms.extend(dm) print('"%s"彈幕爬取完成!(%d條)'%(date,len(dm))) if len(dm) == 0: # 如果為空 break end = dm[-1]['評論時間'].split()[0] # 取最后一條彈幕的日期 if end == date: # 如果最后一條仍為當天,則往下推一天 end = (datetime.datetime.strptime(end,'%Y-%m-%d')-datetime.timedelta(days=1)).strftime('%Y-%m-%d') if end == info[3]: # 如果已經到達上傳那天 break else: date = end dm = get_history(bvid,info[3]) # 避免忽略上傳那天的部分數據 dms.extend(dm) print('彈幕爬取完成!(共%d條)'%len(dms)) print('數據去重中...') dms = del_repeat(dms,'rowID') # 按rowID給彈幕去重 print('數據去重完成!(共%d條)'%len(dms)) return dms
運行主函數:
if __name__ == '__main__': dms = get_dms('BV1HJ411L7DP') dms = pd.DataFrame(dms) dms.to_csv('一路向北.csv',index=False)
爬取過程如下:
感謝你能夠認真閱讀完這篇文章,希望小編分享的“Python如何爬取到B站的彈幕”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。