在写了《Bilibili视频弹幕文件解析》之后,我突然意识到b站弹幕文件会不会就是protobuf,毕竟已经有现有的这么好这么成熟的工具,不聪明才会选择自己实现新的协议。
想到这里,赶紧使用protobuf测试一番。
proto
有了上次的经验,大概知道这个弹幕文件的结构,先写个proto文件,对上b站弹幕文件
dm.proto
syntax = "proto3";
message DmList {
repeated Dm dmList = 1;
}
// 后面的tag数字要对上
message Dm {
int32 stime = 2;
int32 mode = 3;
int32 size = 4;
uint32 color = 5;
string uhash = 6;
string text = 7;
int64 date = 8;
int32 weight = 9;
string action = 10;
int32 pool = 11;
string dmid = 12;
int32 attr = 13;
string animation = 22;
}
使用protoc
生成代码,(关于protoc
的安装,网上教程很多,这里不赘述了)
mkdir pythonout
protoc --python_out=./pythonout ./dm.proto
生成的代码如下
./pythonout/dm_pb2.py
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: dm.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x08\x64m.proto\"\x1d\n\x06\x44mList\x12\x13\n\x06\x64mList\x18\x01 \x03(\x0b\x32\x03.Dm\"\xc6\x01\n\x02\x44m\x12\r\n\x05stime\x18\x02 \x01(\x05\x12\x0c\n\x04mode\x18\x03 \x01(\x05\x12\x0c\n\x04size\x18\x04 \x01(\x05\x12\r\n\x05\x63olor\x18\x05 \x01(\r\x12\r\n\x05uhash\x18\x06 \x01(\t\x12\x0c\n\x04text\x18\x07 \x01(\t\x12\x0c\n\x04\x64\x61te\x18\x08 \x01(\x03\x12\x0e\n\x06weight\x18\t \x01(\x05\x12\x0e\n\x06\x61\x63tion\x18\n \x01(\t\x12\x0c\n\x04pool\x18\x0b \x01(\x05\x12\x0c\n\x04\x64mid\x18\x0c \x01(\t\x12\x0c\n\x04\x61ttr\x18\r \x01(\x05\x12\x11\n\tanimation\x18\x16 \x01(\tb\x06proto3')
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'dm_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_DMLIST._serialized_start=12
_DMLIST._serialized_end=41
_DM._serialized_start=44
_DM._serialized_end=242
# @@protoc_insertion_point(module_scope)
不得不说,protoc
生成的python代码比golang简洁很多,我第一眼看到的这么代码行数这么少,还以为遇到什么意外了呢
使用dm_pb2
新建一个项目,拷贝./pythonout/dm_pb2.py
这个文件到项目路径下以使用生成的pb代码
python要先安装protobuf包(pip install protobuf
)
import dm_pb2
def main():
dm_list_class = getattr(dm_pb2, 'DmList')
dm_list = dm_list_class()
# 这里的seg.so是下载到本地的弹幕文件,如果使用在线的,可以用
# import requests
# dm_list.ParseFromString(requests.get(url).content)
dm_list.ParseFromString(open('seg.so', 'rb').read())
for dm in dm_list.dmList:
print(dm)
if __name__ == '__main__':
main()
运行结果如下:
成功~
总结
上一次折腾了大半天,其实就是写了一个解析protobuf文件的代码。不过也不是完全没有作用,要定义proto的message,需要知道弹幕文件的结构,同时一些字段的tag
必须匹配上,否则偏移不对,无法解析出正确的数据,有了上次的分析结果,这次才能很快的写出proto。