我是個宅男,喜歡看很多人直播,以前可以看一天直播不出門。現在主要看這麼些主播,虎牙的韋神、Dopa,鬥魚的狗賊噓噓。
對於其中的彈幕文化,非常感興趣,就研究下,發現彈幕是用WebSocket實現的,那首先來說說什麼是WebSocket。
WebSocket是什麼
詳細內容可以看看這個問題 https://www.zhihu.com/question/20215561
簡單解釋下:
HTTP 協議是一種無狀態的、無連接的、單向的應用層協議。它採用了請求/響應模型。通信請求只能由客戶端發起,服務端對請求做出應答處理。
這種通信模型有一個弊端:HTTP 協議無法實現服務器主動向客戶端發起消息。大多數 Web 應用程序將通過頻繁的異步JavaScript和XML(AJAX)請求實現長輪詢。輪詢的效率低,非常浪費資源(因爲必須不停連接,或者 HTTP 連接始終打開)。
WebSocket的最大特點就是,服務器可以主動向客戶端推送信息,客戶端也可以主動向服務器發送信息。
WebSocket 如何工作
一個非常典型的WebSocket創建方式如下(來自某巨頭):
function r() { if (!d) { var t = i(); I.info("%cconnecting " + t, p("#0000E3")), u = new WebSocket(t), u.onopen = n, u.onclose = o, u.onerror = a, u.onmessage = h } }
WebSocket獲取龍珠直播彈幕
本次使用的Python第三方庫是 https://github.com/websocket-client/websocket-client
看看官方例子:
import websocket try: import thread except ImportError: import _thread as thread import time def on_message(ws, message): print(message) def on_error(ws, error): print(error) def on_close(ws): print("### closed ###") def on_open(ws): def run(*args): for i in range(3): time.sleep(1) ws.send("Hello %d" % i) time.sleep(1) ws.close() print("thread terminating...") thread.start_new_thread(run, ()) if __name__ == "__main__": websocket.enableTrace(True) ws = websocket.WebSocketApp("ws://echo.websocket.org/", on_message = on_message, on_error = on_error, on_close = on_close) ws.on_open = on_open ws.run_forever()
是不是非常熟悉,和上面講到的一模一樣,4種主要思想方法都是一致的,可以直接調用。
那麼到了實踐環節,本次選取的是龍珠直播,爲啥不是虎牙、鬥魚呢?這個待會再說,我們打開龍珠某個直播間
在網絡裏面選擇ws這一項,即可看到相關連接,而且這些消息是加密過的,別急,我們打開m站試試
這個時候傳輸的彈幕消息已經沒有加密過,直接對比,看到了一條“哈哈哈”的消息,所以我們現在可以確定就是這個websocket連接在傳輸相關消息。
依葫蘆畫瓢,我們嘗試用Python來連接
Curl:
curl 'wss://mbgows.plu.cn:8806/?room_id=2185&group=0' -H 'Pragma: no-cache' -H 'Origin: http://m.longzhu.com' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7' -H 'Sec-WebSocket-Key: n72+EfLt2iSrQ0EswTZ+2A==' -H 'User-Agent: Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Mobile Safari/537.36' -H 'Upgrade: websocket' -H 'Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits' -H 'Cache-Control: no-cache' -H 'Cookie: pluguest=81D781D68480BE065D952CA699B38E6627B61756AEF57338B39053154850A9502BC7FD850F86922BDF3DBD7F774BFDE5CBC80838A34B8F26' -H 'Connection: Upgrade' -H 'Sec-WebSocket-Version: 13' --compressed
Python代碼
#!/usr/bin/env python # -*- coding: utf-8 -*- """ @author: zhangslob @file: longzhu_websocket.py @time: 2018/11/17 @desc: simple websocket client to connect longzhu """ import websocket try: import thread except ImportError: import _thread as thread import time def on_message(ws, message): import json try: print(json.loads(message)) except: print(message) def on_error(ws, error): print(error) def on_close(ws): print("### closed ###") def on_open(ws): pass # def run(*args): # for i in range(3): # time.sleep(1) # ws.send("Hello %d" % i) # time.sleep(1) # ws.close() # print("thread terminating...") # thread.start_new_thread(run, ()) headers = { 'Pragma': 'no-cache', 'Origin': 'http://m.longzhu.com', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7', # 'Sec-WebSocket-Key': 'n72+EfLt2iSrQ0EswTZ+2A==', 'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Mobile Safari/537.36', 'Upgrade': 'websocket', 'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits', 'Cache-Control': 'no-cache', 'Connection': 'Upgrade', 'Sec-WebSocket-Version': '13', } if __name__ == "__main__": websocket.enableTrace(True) ws = websocket.WebSocketApp("wss://mbgows.plu.cn:8806/?room_id=2185&group=0", on_message=on_message, on_error=on_error, on_close=on_close, header=headers) ws.on_open = on_open ws.run_forever()
你可以直接運行上面的代碼,看看會有什麼結果
龍珠直播這個有點奇怪,你根本不用去向服務器發送什麼消息,服務器無腦給你推送彈幕,常見的是客戶端需要先告訴服務器“我是誰”,然後服務器再推送消息給你,並且還有有心跳檢測,“我”告訴服務器我還在看呢,你繼續給我彈幕,看看虎牙和鬥魚。
圖中綠色的是發送的消息,紅色是接受的消息。像這種情況就需要自己去看js代碼是如何處理消息的。鬥魚的話有公開自己的彈幕服務器第三方接入協議。
copy代碼可以閱讀原文