戴兜

戴兜的小屋

Coding the world.
github
bilibili
twitter

B站直播彈幕ws協議分析

image

Chrome DevTools 可以直接查看二進位類型數據包了!

連接#

通過 Chrome DevTools 可以看到,網頁版 B 站直播的彈幕通過 wss://tx-sh3-live-comet-04.chat.bilibili.com/sub 傳輸,這個地址每次是不一樣的。需要通過 https://api.live.bilibili.com/room/v1/Danmu/getConf?room_id=房間號&platform=pc&player=web 獲得 wss 地址(應該是負載均衡的需要,實際測試連接任意 wss 地址都能正常獲取彈幕)

封包頭部 16 個字節用於標識數據包的長度及類型,數據包格式詳見下表。字節序均為大端模式。參考:https://blog.csdn.net/xfgryujk/article/details/80306776

偏移長度類型含義
04int數據包長度
42int數據包頭部長度,固定為 16
62int數據包協議版本(見下文)
84int數據包類型 (見下文)
124int固定為 1
16byte[]數據主體
數據包協議版本含義
0數據包有效負載為未壓縮的 JSON 格式數據
1客戶端心跳包,或伺服器心跳回應(帶有人氣值)
2數據包有效負載為通過 zlib 壓縮後的 JSON 格式數據

客戶端建立連接後,需要在 5 秒內發出加入房間(認證)的數據包,否則會被伺服器強制斷開連接。其中有效負載的 key 字段內容可以從之前的 https://api.live.bilibili.com/room/v1/Danmu/getConf?room_id=房間號&platform=pc&player=web 獲取。如發送的認證包格式錯誤,伺服器會立刻強制斷開連接,JSON 字段的詳細說明見下表。

image

字段類型必選含義
uidnumber×用戶 UID
roomidnumber房間號
protovernumber×協議版本,目前為 2
platformstring×平台,可以是 web
clientverstring×客戶端版本,可以是 “1.8.5”
typenumber×未知,可以是 2
keystring×用戶標識,通過之前提到的接口獲取

心跳#

心跳包建議每 30 秒發一次,頭部 16 字節遵守上文規則,負載內容隨意。(b 站通過傳入一個空對象來生成心跳包,然後就有了我之前無法理解的心跳包內容)

image

通知(彈幕、公告、禮物等)#

有新的彈幕、禮物或其他公告時,伺服器會發送類似下圖的數據包,首先需要使用 zlib.inflate 解壓數據主體部分(除頭部 16 字節外)。解壓後的數據頭部十六字節與原數據頭相同,去除頭部後即為 JSON 格式數據

這裡我們以一個彈幕數據包為例子

image

image

可以看到解壓後的數據依然帶有頭部(16 字節),去除頭部後即為 JSON 格式數據,其中的 cmd 字段更為詳細地描述了數據包類型。其中比較明顯的是,['info'][1] 代表彈幕內容, ['info'][2][1] 為發送者,['info'][9]['ts'] 為發送時間戳,cmd 的已知格式參考下表

cmd 字段含義
DANMU_MSG收到彈幕
SEND_GIFT有人送禮
WELCOME歡迎加入房間
WELCOME_GUARD歡迎房管加入房間
SYS_MSG系統消息
PREPARING主播準備中
LIVE直播開始

下面我展示了幾個常見 cmd 的數據包 JSON 格式,還有很多活動通知 cmd,各位可以自行抓取(如下面的 ACTIVITY_BANNER_UPDATE_V2 就是我寫文章當天出現的活動通知 cmd 類型)

{
  "cmd": "SEND_GIFT",
  "data": {
    "giftName": "辣條",
    "num": 5,
    "uname": "迪多瑪索",
    "face": "http://i2.hdslb.com/bfs/face/1a3b795aafc5887f3f33909c7e66876d23911979.jpg",
    "guard_level": 0,
    "rcost": 42593386,
    "uid": 415822879,
    "top_list": [],
    "timestamp": 1570368091,
    "giftId": 1,
    "giftType": 0,
    "action": "餵食",
    "super": 0,
    "super_gift_num": 0,
    "price": 100,
    "rnd": "EF27025C-4C20-440F-B36F-64CCFABBF68E",
    "newMedal": 0,
    "newTitle": 0,
    "medal": [],
    "title": "",
    "beatId": "",
    "biz_source": "live",
    "metadata": "",
    "remain": 0,
    "gold": 0,
    "silver": 0,
    "eventScore": 0,
    "eventNum": 0,
    "smalltv_msg": [],
    "specialGift": null,
    "notice_msg": [],
    "capsule": null,
    "addFollow": 0,
    "effect_block": 1,
    "coin_type": "silver",
    "total_coin": 500,
    "effect": 0,
    "broadcast_id": 0,
    "draw": 0,
    "crit_prob": 0,
    "tag_image": "",
    "user_count": 0,
    "send_master": null
  }
}
{
  "cmd": "ACTIVITY_BANNER_UPDATE_V2",
  "data": {
    "id": 378,
    "title": "第6名",
    "cover": "",
    "background": "https://i0.hdslb.com/bfs/activity-plat/static/20190904/b5e210ef68e55c042f407870de28894b/14vZu7h9pK.png",
    "jump_url": "https://live.bilibili.com/p/html/live-app-rankcurrent/index.html?is_live_half_webview=1&hybrid_half_ui=1,5,85p,70p,FFE293,0,30,100,10;2,2,320,100p,FFE293,0,30,100,0;4,2,320,100p,FFE293,0,30,100,0;6,5,65p,60p,FFE293,0,30,100,10;5,5,55p,60p,FFE293,0,30,100,10;3,5,85p,70p,FFE293,0,30,100,10;7,5,65p,60p,FFE293,0,30,100,10;&anchor_uid=22550271&is_new_rank_container=1&area_v2_id=163&area_v2_parent_id=3&rank_type=master_realtime_area_hour&area_hour=1",
    "title_color": "#8B5817",
    "closeable": 1,
    "banner_type": 4,
    "weight": 18,
    "add_banner": 0
  }
}
{
  "cmd": "ROOM_REAL_TIME_MESSAGE_UPDATE",
  "data": {
    "roomid": 101526,
    "fans": 294665,
    "red_notice": -1
  }
}

後記:Chrome 支持直接顯示 WebSocket 二進位包真的能節省很多時間。吹爆 Chrome!

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。