Bilibili_解析ProtoBuf格式的彈幕


運行環境

  • python 3.7.4

目標

  • 解析Bilibili彈幕

不知道從什么時候開始,嗶哩嗶哩的彈幕就變成ProtoBuf的格式了,如果對這個格式不了解,就會覺得爬下來的是一堆亂碼,難以處理。

由於最近期末論文是個爬蟲,所以就整理了一下解析的方法,發出來分享。

主要之前查找資料時,沒有看到過python解析的方法,所以分享一下。其它語言可以到github上搜DmSegMobileReply,就會有其它語言的方法。

介紹一下ProtoBuf

2008年,可能更早,Google推出了Protocol Buffers。那時候我還小,不太清楚這段歷史,網上也沒有很多資料,有了解過的大佬還奢望能科普一下。

總之,這是一種數據格式,可以類比於xml、json等。

我們要解析一份ProtoBuf數據,需要一份參照文檔,也就是消息定義文檔,這可以類比於對象(class)。

后台通常用一份.proto為擴展名的文件來定義消息,而前端則以json格式來存放這份參照文檔。Bilibili的參照文檔是這樣子的。

{
  "DmSegMobileReply": {
    "fields": {
      "elems": {
        "rule": "repeated",
        "type": "DanmakuElem",
        "id": 1
      }
    }
  },
  "DanmakuElem": {
    "fields": {
      "id": {"type": "int64","id": 1},
      "progress": {"type": "int32","id": 2},
      "mode": {"type": "int32","id": 3},
      "fontsize": {"type": "int32","id": 4},
      "color": {"type": "uint32","id": 5},
      "midHash": {"type": "string","id": 6},
      "content": {"type": "string","id": 7},
      "ctime": {"type": "int64","id": 8},
      "weight": {"type": "int32","id": 9},
      "action": {"type": "string","id": 10},
      "pool": {"type": "int32","id": 11},
      "idStr": {"type": "string","id": 12},
      "attr": {"type": "int32","id": 13}}}
}

Bilibili為什么使用ProtoBuf取代原先的xml,大概是為了壓縮彈幕數據,提高彈幕上限吧。

至於ProtoBuf為什么可以減少數據量,可以看其它博客或者官方文檔。

以《天官賜福》為例做彈幕解析

一、爬取數據

url = "https://api.bilibili.com/x/v2/dm/web/seg.so?type=1&oid=253627085&pid=712552253&segment_index=1"
import requests
with open("./message","wb") as f:
    f.write(requests.get(url).content)

沒有解析的數據如下:

L������H��
 (���220d3f395:	嗚嗚嗚@����Hb40756202282418179p���
f�������HǑ
 (���22f369812:$為你戰死是至高無上的榮耀@����Hb40757157776326659p�ޱU
a�������H�� (���29d69092a:靈文姐姐保我期中高分@����H	b40758306907619333p����

二、解析字幕

1、安裝protoc

注. macOS brew install應該就可以了。以下介紹的安裝方法不一定簡便,而且更多針對的是linux,僅供參考。

我是直接下載的源碼,然后編譯,不過需要c++的編譯環境和一些相關工具。如果不想安裝的話,就可以直接在github上下載release版本。

這里稍微介紹一下怎么安裝,先克隆倉庫。

git clone --depth=1 https://github.com.cnpmjs.org/protocolbuffers/protobuf.git

考慮到github在國內特別慢,建議用鏡像並且只克隆最近一次commit,不過安全性需要自己考量一下。

接下來按照github上的這個教程完成如下幾步。

  1. 安裝編譯環境和工具(這是linux系統下的方法)

    sudo apt-get install autoconf automake libtool curl make g++ unzip
    
  2. 修改子模塊的倉庫路徑

    cd <protobuf下載路徑>/protobuf
    vim .gitmodules
    

    替換url,修改完如下:

    [submodule "third_party/benchmark"]
            path = third_party/benchmark
            url = https://github.com.cnpmjs.org/google/benchmark.git
    [submodule "third_party/googletest"]
            path = third_party/googletest
            url = https://github.com.cnpmjs.org/google/googletest.git
            ignore = dirty
    
  3. 初始化

    cd <protobuf下載路徑>/protobuf
    git submodule update --init --recursive
    ./autogen.sh
    
  4. 安裝protoc

    cd <protobuf下載路徑>/protobuf
    ./configure
    make
    make check
    sudo make install
    sudo ldconfig
    
  5. 驗證

    protoc --version
    

    如果安裝成功,就會顯示版本號。

2、安裝python第三方庫 - google.protobuf

參照這個教程

cd <protobuf下載路徑>/protobuf/python
python setup.py build
python setup.py test
python setup.py install

3、生成python解析文件

因為我們已經有一個json格式的消息定義,所以現在需要把它轉成.proto為后綴的文件,命名為dm.proto。轉化完的文件如下:

syntax = "proto3";

package dm;

message DmSegMobileReply{
    repeated DanmakuElem elems=1;
}
message DanmakuElem{
    int64 id = 1;
    int32 progress = 2;
    int32 mode = 3;
    int32 fontsize = 4;
    uint32 color = 5;
    string midHash = 6;
    string content = 7;
    int64 ctime = 8;
    int32 weight = 9;
    string action = 10;
    int32 pool = 11;
    string idStr = 12;
}

利用protoc工具將其編譯為python解析文件。

protoc --python_out=./ ./dm.proto

4、解析彈幕

執行完上面語句,就會拿到一份dm_pb2.py文件,我們需要在解析字幕的時候引用他。使用方法如下:

from dm_pb2 import DmSegMobileReply
from google.protobuf.json_format import MessageToJson,Parse
import json
DM = DmSegMobileReply()
with open("./message","rb") as f:
    DM.ParseFromString(f.read())

with open("./message.json","w") as f:
    f.write(json.dumps(json.loads(MessageToJson(DM)),ensure_ascii=False))

最后的解析結果:

{"elems": [{"id": "40756202282418179", "progress": 222379, "mode": 1, "fontsize": 25, "color": 16777215, "midHash": "20d3f395", "content": "嗚嗚嗚", "ctime": "1604878461", "weight": 1, "idStr": "40756202282418179"}, {"id": "40757157776326659", "progress": 215239, "mode": 1, "fontsize": 25, "color": 16777215, "midHash": "2f369812", "content": "為你戰死是至高無上的榮耀", "ctime": "1604880284", "weight": 1, "idStr": "40757157776326659"}, {"id": "40758306907619333", "progress": 348984, "mode": 1, "fontsize": 25, "color": 16777215, "midHash": "9d69092a", "content": "靈文姐姐保我期中高分", "ctime": "1604882475", "weight": 9, "idStr": "40758306907619333"}, {"id": "40758308418093059", "progress": 325174, "mode": 1, "fontsize": 25, "color": 16777215, "midHash": "155c80d8", "content": "靈文姐姐保我們期中考高分✧(≖ ◡ ≖✿)", "ctime": "1604882478", "weight": 1, "idStr": "40758308418093059"}, {"id": "40758855406714887", "progress": 346591, "mode": 1, "fontsize": 25, "color": 16777215, "midHash": "b22a34e2", "content": "靈文姐姐保我期中高分",...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM