
本文详解如何使用 protocol buffers(proto2)定义文件生成 python 类,解析二进制响应为可读的字典或对象,并提供完整流程、代码示例与关键注意事项。
本文详解如何使用 protocol buffers(proto2)定义文件生成 python 类,解析二进制响应为可读的字典或对象,并提供完整流程、代码示例与关键注意事项。
当调用如 Apple CLS 定位服务(https://gs-loc.apple.com/clls/wloc)等私有/内部 API 时,响应常以紧凑高效的 Protocol Buffer(Proto2)二进制格式返回(如 b"\x125\n\x1164:fb:...")。这类数据无法直接用 json.loads() 或 str() 解析——它不是文本,而是结构化二进制序列化结果。正确解码的前提是:你必须拥有与该 API 响应完全匹配的 .proto 文件(即协议定义)。
? 核心前提:获取并验证 .proto 文件
Proto2 解码依赖严格的 schema 匹配。例如,若响应包含 Wi-Fi 接入点列表(MAC 地址、信号强度、时间戳等),其 .proto 文件可能类似:
// wloc_response.proto (Proto2 syntax)
syntax = "proto2";
message AccessPoint {
optional string mac_address = 1;
optional int32 signal_strength = 2;
optional int64 timestamp = 3;
optional int32 channel = 4;
}
message WLocResponse {
repeated AccessPoint aps = 1;
}⚠️ 注意:没有正确的 .proto 文件,任何“猜测式”解码都极大概率失败或产生乱码。Apple 等厂商通常不公开此类定义,需通过官方 SDK、逆向分析或内部文档获取。
? 解码全流程(Python)
1. 安装 Protobuf 工具链
pip install protobuf # 需额外安装 protoc 编译器(非 Python 包): # macOS: brew install protobuf # Ubuntu: sudo apt-get install protobuf-compiler # Windows: 下载 protoc-win-x64.zip 并添加到 PATH
2. 编译 .proto 生成 Python 类
假设已获得 wloc_response.proto,执行:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
protoc --python_out=. wloc_response.proto
将生成 wloc_response_pb2.py(含自动生成的 WLocResponse 类)。
3. 在 Python 中解析响应
import requests
from wloc_response_pb2 import WLocResponse # 导入生成的类
HEADERS = { ... } # 实际请求头
DATA = b"..." # 实际请求体
r = requests.post(
'https://gs-loc.apple.com/clls/wloc',
headers=HEADERS,
data=DATA,
verify=False # ⚠️ 生产环境请勿禁用证书验证!
)
# 关键:用生成的类反序列化二进制内容
response_obj = WLocResponse()
response_obj.ParseFromString(r.content) # 核心解码步骤
# 转换为嵌套字典(便于调试/后续处理)
def proto_to_dict(obj):
from google.protobuf.json_format import MessageToDict
return MessageToDict(obj, preserving_proto_field_name=True, including_default_value_fields=True)
result_dict = proto_to_dict(response_obj)
print(result_dict)
# 输出示例:{'aps': [{'mac_address': '64:fb:92:9c:91:8d', 'signal_strength': -72, 'timestamp': 1712345678901, ...}, ...]}4. 直接访问属性(更高效)
for ap in response_obj.aps:
print(f"MAC: {ap.mac_address}, RSSI: {ap.signal_strength}, TS: {ap.timestamp}")⚠️ 关键注意事项
-
版本一致性:确保
protoc编译器版本与protobufPython 包版本兼容(建议均使用 v3.20+,虽支持 Proto2 语法)。 -
字段缺失处理:Proto2 中
optional字段若未返回,访问时返回默认值(如0,"",False),需用HasField('field_name')显式判断是否存在。 -
安全性警告:示例中
verify=False仅用于调试,生产环境必须启用 TLS 证书验证,否则面临中间人攻击风险。 -
无 .proto 文件? 若无法获取定义,可尝试:
- 使用
protoc --decode_raw查看原始字段编号与类型(但无法还原字段名); - 结合网络抓包(如 Charles Proxy)分析响应结构;
- 参考开源项目(如 apple-wifi-locate)中逆向的
.proto文件(注意合规性)。
- 使用
✅ 总结
解码 Proto2 响应的本质是 schema 驱动的反序列化:.proto 文件是钥匙,protoc 是铸钥工具,ParseFromString() 是开锁动作。跳过 schema 步骤的“强行解码”注定失败。始终优先确认协议定义来源,再按流程生成、解析、验证,即可将神秘的二进制流转化为清晰可用的 Python 对象。

















