如何使用requests模块登录需提交非常规POST payload的grpc-web站点
解决方案
问题本质
这个站点的登录接口使用的是gRPC-Web + Protobuf协议,你抓包看到的乱码payload是Protobuf序列化后的二进制数据,不是常规的键值对格式,因此不能直接用Python字典构造payload。
具体操作步骤
- 第一步:获取接口对应的Protobuf定义文件(.proto后缀)
你要请求的接口路径是/checkout.CheckoutV1/logInWithEmail,对应的proto文件可以从站点前端打包的JS源码中检索checkout.CheckoutV1关键字获取,文件中会明确定义登录请求的结构体,结构参考如下:syntax = "proto3"; package checkout; service CheckoutV1 { rpc logInWithEmail(LogInWithEmailRequest) returns (LogInWithEmailResponse); } message LogInWithEmailRequest { string email = 1; string password = 2; // 其他可选字段根据实际proto定义补充 } message LogInWithEmailResponse { // 响应字段根据实际proto定义补充 } - 第二步:编译proto文件生成Python调用代码
先安装依赖包:
执行编译命令,假设你的proto文件命名为pip install grpcio grpcio-toolscheckout.proto:
执行后会生成python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. checkout.protocheckout_pb2.py和checkout_pb2_grpc.py两个可用的Python文件。 - 第三步:构造符合gRPC-Web规范的payload
gRPC-Web的请求有固定帧结构:1字节压缩标志位 + 4字节大端序的Protobuf数据长度 + 序列化后的Protobuf二进制数据。 - 第四步:修改登录请求代码
参考代码如下:import requests import struct import checkout_pb2 start_url = 'https://www.aboutyou.cz/' post_link = 'https://grips-web.aboutyou.com/checkout.CheckoutV1/logInWithEmail' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36', 'Content-Type': 'application/grpc-web+proto', 'Origin': 'https://www.aboutyou.cz', 'Referer': 'https://www.aboutyou.cz/', 'X-Grpc-Web': '1' } with requests.Session() as s: # 先访问首页拿到Cloudflare等必要Cookie s.get(start_url) s.headers.update(headers) # 填充登录参数 login_req = checkout_pb2.LogInWithEmailRequest() login_req.email = "你的实际登录邮箱" login_req.password = "你的实际登录密码" # 序列化Protobuf数据 proto_data = login_req.SerializeToString() # 构造gRPC-Web帧头:1字节0表示未压缩 + 4字节大端序的Protobuf数据长度 frame_header = struct.pack('>BI', 0, len(proto_data)) # 拼接得到最终请求payload payload = frame_header + proto_data # 发送登录请求 r = s.post(post_link, data=payload) print("请求状态码:", r.status_code) # 如需解析响应,先去掉前5字节的响应帧头,再用响应类反序列化 if r.status_code == 200: resp_proto = r.content[5:] login_resp = checkout_pb2.LogInWithEmailResponse() login_resp.ParseFromString(resp_proto) print("登录响应:", login_resp)
注意事项
- 如果请求被Cloudflare拦截,需要先通过Cloudflare人机验证拿到有效的
__cf_bm等Cookie后再发送登录请求,也可以使用undetected-chromedriver等工具绕过反爬检测。 - 请确保你获取的proto文件定义和站点当前使用的版本一致,否则会出现序列化数据不匹配、请求失败的问题。
内容的提问来源于stack exchange,提问作者MITHU
相关产品推荐
相关产品推荐

