Chrome DevTools 可以直接查看 binary 类型数据包了!
连接#
通过 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
偏移 | 长度 | 类型 | 含义 |
---|---|---|---|
0 | 4 | int | 数据包长度 |
4 | 2 | int | 数据包头部长度,固定为 16 |
6 | 2 | int | 数据包协议版本(见下文) |
8 | 4 | int | 数据包类型 (见下文) |
12 | 4 | int | 固定为 1 |
16 | – | byte[] | 数据主体 |
数据包协议版本 | 含义 |
---|---|
0 | 数据包有效负载为未压缩的 JSON 格式数据 |
1 | 客户端心跳包,或服务器心跳回应(带有人气值) |
2 | 数据包有效负载为通过 zlib 压缩后的 JSON 格式数据 |
客户端建立连接后,需要在 5 秒内发出加入房间(认证)的数据包,否则会被服务器强制断开连接。其中有效负载的 key 字段内容可以从之前的 https://api.live.bilibili.com/room/v1/Danmu/getConf?room_id=房间号&platform=pc&player=web
获取。如发送的认证包格式错误,服务器会立刻强制断开连接,JSON 字段的详细说明见下表。
字段 | 类型 | 必选 | 含义 |
---|---|---|---|
uid | number | × | 用户 UID |
roomid | number | √ | 房间号 |
protover | number | × | 协议版本,目前为 2 |
platform | string | × | 平台,可以是 web |
clientver | string | × | 客户端版本,可以是 “1.8.5” |
type | number | × | 未知,可以是 2 |
key | string | × | 用户标识,通过之前提到的接口获取 |
心跳#
心跳包建议每 30 秒发一次,头部 16 字节遵守上文规则,负载内容随意。(b 站通过传入一个空对象来生成心跳包,然后就有了我之前无法理解的心跳包内容)
通知(弹幕、公告、礼物等)#
有新的弹幕、礼物或其他公告时,服务器会发送类似下图的数据包,首先需要使用 zlib.inflate
解压数据主体部分(除头部 16 字节外)。解压后的数据头部十六字节与原数据头相同,去除头部后即为 JSON 格式数据
这里我们以一个弹幕数据包为例子
可以看到解压后的数据依然带有头部(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!