某方数据库protobuf详解
1. 什么是protobuf
Protobuf 是由 Google 开发的一种语言无关,平台无关,可扩展的序列化结构数据的方法,可用于通信和数据存储。提到 Protobuf 就不得不提到 序列化和反序列化 的概念。序列化和反序列化属于通信协议的一部分,它们位于 TCP/IP 四层模型中的应用层和 OSI 七层模型中的表示层。序列化是把应用层的对象转换为二进制串,反序列化是把二进制串转化成应用层的对象。这里详细分析请看 参考文章3。
1.1 protobuf实现方法1:protoc
-
安装protoc
- 点击下载

- 解压后将
bin目录路径添加到系统环境变量中

- 点击下载
-
编译proto文件
-
proto文件示例
protosyntax = "proto3"; // 定义消息类型 message Person { string name = 1; // 姓名 int32 age = 2; // 年龄 string email = 3; // 邮箱 repeated string hobbies = 4; // 爱好列表 Address address = 5; // 嵌套消息 } // 定义嵌套消息 message Address { string city = 1; string street = 2; int32 zipcode = 3; } // 定义响应消息 message PersonResponse { int32 code = 1; string message = 2; Person data = 3; } -
编译proto文件
cmdprotoc --python_out=. person.proto
-
-
在python中导入
pythonimport person_pb2 # ========== 序列化:创建对象并转换为字节 ========== print("=" * 50) print("1. 序列化示例") print("=" * 50) # 创建 Person 对象 person = person_pb2.Person() person.name = "张三" person.age = 25 person.email = "zhangsan@example.com" person.hobbies.extend(["读书", "游泳", "编程"]) # 创建嵌套的 Address 对象 person.address.city = "北京" person.address.street = "朝阳路123号" person.address.zipcode = 100000 # 打印对象内容 print("原始对象:") print(f" 姓名: {person.name}") print(f" 年龄: {person.age}") print(f" 邮箱: {person.email}") print(f" 爱好: {', '.join(person.hobbies)}") print(f" 地址: {person.address.city}{person.address.street}, {person.address.zipcode}") # 序列化为字节串 serialized_data = person.SerializeToString() print(f"\n序列化后的字节串长度: {len(serialized_data)} 字节") print(f"字节串(前50字节): {serialized_data[:50]}") # 写入文件 with open('person.bin', 'wb') as f: f.write(serialized_data) print("已写入 person.bin 文件") # ========== 反序列化:从字节恢复对象 ========== print("\n" + "=" * 50) print("2. 反序列化示例") print("=" * 50) # 创建新的空对象 new_person = person_pb2.Person() # 从字节串解析 new_person.ParseFromString(serialized_data) # 打印恢复后的对象 print("反序列化后的对象:") print(f" 姓名: {new_person.name}") print(f" 年龄: {new_person.age}") print(f" 邮箱: {new_person.email}") print(f" 爱好: {', '.join(new_person.hobbies)}") print(f" 地址: {new_person.address.city}{new_person.address.street}, {new_person.address.zipcode}") # ========== 验证数据一致性 ========== print("\n" + "=" * 50) print("3. 数据一致性验证") print("=" * 50) assert person.name == new_person.name assert person.age == new_person.age assert person.email == new_person.email assert list(person.hobbies) == list(new_person.hobbies) assert person.address.city == new_person.address.city print("✓ 所有字段验证通过!")
1.2 protobuf实现方法2:blackboxprotobuf
-
安装blackboxprotobuf
cmd# 这里我记得有个问题,就是blackboxprotobuf与protoc的某个依赖包版本冲突,使用的时候可能会遇到 pip install blackboxprotobuf -
导入blackboxprotobuf
pythonimport blackboxprotobuf import json # 反序列化 with open(r"person.bin", "rb") as fp: data = fp.read() print(f"原始序列化后的字节串: {data}") print(f"原始序列化后的字节串长度: {len(data)} 字节") deserialize_data, message_type = blackboxprotobuf.protobuf_to_json(data) print(f"原始数据: {deserialize_data}") print(f"消息类型: {message_type}") # 消息类型 # 序列化,注意数据类型解析错误需要手动处理 deserialize_data = json.loads(deserialize_data) deserialize_data["2"] = int(deserialize_data["2"]) deserialize_data["5"]["3"] = int(deserialize_data["5"]["3"]) serialized_data = blackboxprotobuf.encode_message(deserialize_data, message_type) print(f"序列化后的字节串: {serialized_data}") print(f"序列化后的字节串长度: {len(serialized_data)} 字节") # ========== 验证数据一致性 ========== print("\n" + "=" * 50) print("3. 数据一致性验证") print("=" * 50) assert serialized_data == data print("✓ 所有字段验证通过!")
2. 某方数据库protobuf实现
案例地址: aHR0cHM6Ly9zLndhbmZhbmdkYXRhLmNvbS5jbi9wYXBlcj9xPSVFNSU5QiVCNCVFNiVBMyU4Qg==
2.1 搜索参数生成
这里详细分析请看 参考文章1
-
定义proto文件
-
调试找到序列化的代码,代码是逐层嵌套的,每个字段都有一个对应的proto类型,逐层跟进处理。

-
根据原始参数,定义proto文件
protosyntax = "proto3"; message SearchService { enum InterfaceType { A = 0; } enum SearchScope { B = 0; } enum SearchFilter { C = 0; } enum Order { D = 0; } message SearchSort { string field = 1; Order order = 2; } message SecondsList { string Field = 1; string Value = 2; } message Commonrequest { string searchType = 1; string searchWord = 2; SearchSort searchSort = 3; repeated SecondsList secondslist = 4; int32 currentPage = 5; int32 pageSize = 6; SearchScope searchScope = 7; repeated SearchFilter searchFilter = 8; bool LanguageExpand = 9; bool TopicExpand = 10; bool semantic_retrieval = 11; string channel = 12; string module = 13; } message SearchRequest { Commonrequest commonrequest = 1; // 任意变量名 InterfaceType interfaceType = 2; // 任意变量名 repeated string optional_discovery_type = 4; // 任意变量名 } }
-
-
编译proto文件
cmdprotoc --python_out=. xx.proto
2.2 响应数据分析
-
方法1: 使用
blackboxprotobuf解析响应数据编写proto文件-
根据
message_data 和 message_type确定响应类型和内容,定义对应的proto文件。pythonmessage_data, message_type = blackboxprotobuf.protobuf_to_json(response.content[5:]) print("message_data:\n", message_data) print("message_type:\n", message_type)
-
-
方法2: 调试找到反序列化的代码,代码是逐层嵌套的,每个字段都有一个对应的proto类型,逐层跟进处理。
- 这里详细分析请看
参考文章1,我是失败了,需要耐心调试和擅长AST。希望大佬路过多多指点😁

- 这里详细分析请看
-
定义proto文件
proto// 我的想法是我并不需要定义完整的proto文件,我只需要通过方法1定义出我需要的字段即可,示例: syntax = "proto3"; message SearchServiceResponse { repeated Item field_4 = 4; message Item { oneof content { Periodical periodical = 101; Patent patent = 119; } } message Periodical { string author_cn = 3; // 中文作者名 string author_en = 6; // 英文作者名 } message Patent { repeated string inventors = 5; // 发明人列表 } }
2.3 完整代码示例
python
import xx_pb2 as pb #导入包
import xx_parse_pb2 as pb_test #导入包
from google.protobuf.json_format import MessageToJson
import requests
import blackboxprotobuf
SearchRequest= pb.SearchService.SearchRequest() #实例化对象S
#按上面解析数据,按照对应的属性设置值
#字符串,数字型的都是直接赋值
SearchRequest.commonrequest.searchType = 'periodical'
SearchRequest.commonrequest.searchWord = '围棋'
SearchRequest.commonrequest.currentPage = 1
SearchRequest.commonrequest.pageSize = 10
SearchRequest.commonrequest.searchSort.field = "出版时间"
SearchRequest.commonrequest.searchSort.order = 1
SearchRequest.commonrequest.searchScope = 0
SearchRequest.commonrequest.channel = 'pc'
SearchRequest.commonrequest.module = 'search'
#repeated修饰的messsage类型和enum类型,则需要稍微多几个步骤
SearchRequest.interfaceType = 1
SearchRequest.optional_discovery_type.extend(['AI_READ', 'AI_EXTRACT'])
print(MessageToJson(SearchRequest))
form_data = SearchRequest.SerializeToString()
# print(form_data)
bytes_head = bytes([0, 0, 0, 0, len(form_data)])
data=bytes_head+form_data
# print(data)
headers = {
"Accept": "*/*",
"Accept-Language": "zh-CN,zh;q=0.9,zh-TW;q=0.8",
"Content-Type": "application/grpc-web+proto",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
}
url = "https://xxxx/SearchService.SearchService/search"
response=requests.post(url,headers=headers,data=bytes_head+form_data)
message_data, message_type = blackboxprotobuf.protobuf_to_json(response.content[5:])
print("message_data:\n", message_data)
print("message_type:\n", message_type)