1. 程式人生 > >【Python3爬蟲】鬥魚彈幕爬蟲

【Python3爬蟲】鬥魚彈幕爬蟲

在網上找到了一份鬥魚彈幕伺服器第三方接入協議v1.6.2,有了第三方介面,做起來就容易多了。

 

一、協議分析

鬥魚後臺協議頭設計如下:

 

這裡的訊息長度是我們傳送的資料部分的長度和頭部的長度之和,兩個訊息長度是一樣。然後要注意的是該協議使用的是小端整數,所以我們要對資料進行處理後再發送,這裡可以使用int.to_bytes()將整數轉變成小端整數的形式。示例如下:

int.to_bytes(12,4,'little')   # b'\x0c\x00\x00\x00'

int.to_bytes(12,4,'big')     # b'\x00\x00\x00\x0c'

然後訊息型別是689(689表示客戶端傳送給伺服器,690表示伺服器傳送給客戶端),加密欄位和保留欄位都是預設為0。這裡由於訊息型別是兩個位元組的,加密欄位和保留欄位都是一個位元組,但是因為加密欄位和保留欄位都是0,所以這四個位元組可以使用int.to_bytes(689,4,'little')來表示。最後該協議使用的是utf-8編碼,所以我們需要對整個資料進行編碼後再發送。

 

二、具體步驟

1、連線伺服器

第三方客戶端通過 TCP 協議連線到彈幕伺服器(依據指定的 IP 和埠),其中IP 地址為openbarrage.douyutv.com,埠為8601,相關程式碼如下:

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostbyname("openbarrage.douyutv.com")
port = 8601
client.connect((host, port))

2、傳送登入請求

客戶端向彈幕伺服器傳送登入請求,登入彈幕伺服器,格式如下:

[email protected]=loginreq/[email protected]=房間號/

3、傳送加組請求

客戶端收到登入成功訊息後傳送進入彈幕分組請求給彈幕伺服器,格式如下:

[email protected]=joingroup/[email protected]=房間號/[email protected]=-9999/

gid表示分組號,第三方平臺建議選擇-9999即海量彈幕模式。

4、接收廣播訊息

接收伺服器傳送的廣播訊息,包括使用者發的彈幕和送的禮物資訊,然後解析得到具體的內容。但這些資料裡只有禮物的id而沒有具體的禮物名稱,然後我通過抓包找到了兩個連結,裡面包含了禮物id和名稱的對應關係,相關程式碼如下:

 1 gift_dict = {}
 2 headers = {
 3     "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36"
 4 }
 5 url1 = "https://webconf.douyucdn.cn/resource/common/gift/flash/gift_effect.json"
 6 res1 = requests.get(url1, headers=headers)
 7 js1 = json.loads(res1.text.lstrip('DYConfigCallback(').rstrip(');'))
 8 gift_data1 = js1['data']['flashConfig']
 9 for i in gift_data1.keys():
10     gift_dict[gift_data1[i]['id']] = gift_data1[i]['name']
11 
12 url2 = "https://webconf.douyucdn.cn/resource/common/prop_gift_list/prop_gift_config.json"
13 res2 = requests.get(url2, headers=headers)
14 js2 = json.loads(res2.text.lstrip('DYConfigCallback(').rstrip(');'))
15 gift_data2 = js2['data']
16 for i in gift_data2.keys():
17     gift_dict[int(i)] = gift_data2[i]['name']

5、傳送心跳訊息

客戶端每隔45秒給伺服器傳送一次心跳訊息,用於維護和伺服器後臺間的聯絡,格式如下:

keep_msg = "[email protected]=keeplive/[email protected]=十位時間戳"  # 舊版心跳訊息
keep_msg = "mrkl/" # 新版心跳訊息

6、核心程式碼

在傳送資料的時候,有可能會出現一次無法傳送完的情況,所以就需要多傳送幾次,確保把資料都發送出去:

 1 msg = msg + '\0'  # 資料以'\0'結尾
 2 msg = msg.encode('utf-8')  # 使用utf-8編碼
 3 length = len(msg) + 8  # 訊息長度
 4 code = 689  # 訊息型別
 5 # 訊息頭部:訊息長度+訊息長度+訊息型別+加密欄位(預設為0)+保留欄位(預設為0)
 6 head = int.to_bytes(length, 4, 'little') + int.to_bytes(length, 4, 'little') + int.to_bytes(code, 4, 'little')
 7 # 傳送頭部部分
 8 client.send(head)
 9 # 傳送資料部分
10 sent = 0
11 while sent < len(msg):
12     n = client.send(msg[sent:])  # 返回已傳送的資料長度
13     sent = sent + n

 

三、執行結果

執行截圖:

進入資料庫檢視結果:

db.getCollection('DouYu-6039226').find({"data_type":"gift"})

結果如下:

還可以看看大家都發了什麼彈幕:

db.getCollection('DouYu-6039226').find({"data_type":"chat"},{"user_name":1,"chat_txt":1,"_id":0})

結果如下:

 

完整程式碼已上傳到GitHub:https://github.com/QAQ112233/DouYu