一、 项目背景
齐鲁工业大学 23 号楼下的充电桩由威胜集团提供技术支持。由于官方小程序仅支持近距离扫码查看,无法远程获知全场 70 多个桩位的实时状态。在北方的严冬深夜,为了找一个空桩而在寒风中逐一尝试显然不是最优解。
本项目旨在通过 Python 逆向监测,将全场状态聚合为一个实时更新的可视化看板。

二、 协议逆向全流程
1. 流量嗅探与抓包
使用 Fiddler 对微信小程序进行 SSL 解密。通过分析发现,查询一个充电桩的状态需要遵循严格的顺序逻辑:
- 第一步:Session 激活 (AddSession)
告知服务器“我要查看某个桩”。如果跳过此步直接取数,后端会报错。 - 第二步:数据拉取 (getWxInfo)
服务器根据当前 Session 绑定的设备 ID,返回详细的 JSON 数据(包含剩余时间、占用状态等)。
2. 身份凭证拆解
接口校验的核心在于 Header 中的 Cookie:
ASP.NET_SessionId: 服务端生成的会话标识,具有时效性。OpenID: 用户在微信生态下的唯一标识。
三、 核心架构设计
1. 负载均衡与 Cookie 池
由于单 Session 存在严重的频率限制,且极易因“操作频繁”被封禁。我设计了一个 Cookie 池 (Cookie Pool)。
通过维护多个有效的 Session,系统可以利用多线程并发技术,将 70 个点位的查询压力平摊给多个“虚拟用户”。
2. 关键代码片段
A. 核心通信逻辑
这是避开 .NET 后台 NullReferenceException 报错的关键。必须保证 Body 中的 openid 与 Cookie 严格一致。
1 | def fetch_status(device_id, cookie, openid): |
B. 多线程任务调度
使用 Queue 队列实现生产者-消费者模型。
1 | def worker(cookie, task_queue): |
四、 坑位总结 (Post-Mortem)
1. 致命的 500 错误
现象:程序运行初期,频繁收到服务器返回的 HTML 错误页面,提示“未将对象引用设置到对象的实例”。
分析:威胜后台代码鲁棒性不足。当 AddSession 与 getWxInfo 之间的调用间隔过短,或者 openid 参数大小写不敏感时,后端无法在内存中初始化用户对象。
解决:严格对齐参数,并在两步操作间加入 0.5 秒的微小延迟。
2. 动态 Session 过期
现象:脚本运行数小时后,所有桩位显示“离线”。
解决:编写了一个 Cookie Check 脚本。每隔一小时对池内 Cookie 进行“健康检查”,若失效则通过钉钉或企业微信机器人提醒手动更新抓包。
五、伦理与安全性思考
1 | 本项目的初衷是公共数据透明化,而非恶意攻击。在实现过程中,我严格限制了请求频率(单个 Cookie 间隔 10s 以上),确保不对官方服务器造成额外压力。 |
六、 项目成果
通过这套系统,全场 70 个充电桩的巡检周期从手工扫码(约 1 小时)缩短到了自动化轮询(约 3 分钟)。
可视化看板不仅能显示哪个桩空着,还能通过 sytime 字段预测该桩位何时会释放,极大地优化了排队体验。

技术栈: Python / Flask / Requests / Fiddler / Threading