8.9 KiB
虎牙精英宝典 HAR 重新分析(Python)
1. 样本与结论
| HAR | SHA-256 | entries | 结论 |
|---|---|---|---|
手机扫码登录-pc直播间-1.har |
bcb1e830bfc368c9029f85f90458b708dcf086993a79b833e8e544c65e5c679f |
1947 | 扫码登录、PC 直播间初始化、登录态建立 |
pc直播间-精英宝典1.har |
f8d13a837c477aa4dc55b27df6828ffb7840bbdcccf7c078f840164d62a00e07 |
580 | 精英宝典初始化、绑定、任务、奖品、积分、记录、商城前置 |
页面地址为 https://zt.huya.com/b02faae1/pc/index.html。活动固定业务参数为 sid=2203、actId=25135、绑定活动 bActId=9271、任务模块 moduleId=20051、游戏 cjm、组件 gid/componentId=3203。
核心结论:协议是 WSS 二进制通道承载的 WUP/TAF RPC,HTTP cdnws.api.huya.com 可作为现有 Python 客户端的兜底。样本没有捕获积分兑换成功请求、兑换详情响应或支付完成闭环,因此这些字段不能从 HAR 推测。
2. 传输层与帧解码
- 活动页主通道:
wss://wsapi.huya.com/?baseinfo=<动态值>。 - 直播间/绑定入口还使用
wss://d35bf35c-ws.va.huya.com/?baseinfo=<动态值>。 - HTTP 兜底:
POST https://cdnws.api.huya.com/?baseinfo=<动态值>,请求体为 WUP 包。 - HAR 的业务消息在 entry 的
_webSocketMessages,不是普通 HTTP entry body。 - WebSocket 帧前 6 字节是通道头(command、sequence),后续 body 再提取 WUP;WUP body 从
0x10 0x03字段开始。仓库的WssMessage.decode()、frame_decoder._extract_wup()和WupResponse.decode()可以复用。 launch.wsLaunch、mobileui.getConfig完成连接初始化;业务 WUPrequestId在同一会话中递增,不能写死 HAR 值。
3. 请求链
精英宝典 WebSocket entry 75 的可复现顺序如下:
launch.wsLaunch->mobileui.getConfig。GameBizUI.getQiWeiRelationByUid(页面辅助信息)。webActUI.checkUserBindGameAccount(bActId=9271),返回和平精英、微信/QQ 平台、角色绑定状态。- 并行查询:
getActPrizeList(sid=2203)、getActInfo(actId=25135)、getActTaskDetail(actId=25135)。 getActUserTaskDetail(userId, actId=25135)、getUserScore(sid=2203)。- 绑定流程:再次检查绑定 ->
huyauserui.getUserProfileBatch->getLiveLinkParam(bActId=9271)->confirmBindActAccount(bActId=9271)-> 再次检查绑定。 - 记录页:
getUserPrizeRecords(sid=2203)->getEntityPrizeFieldMap->getModuleAddress(moduleId=20051)。 - 商城前置:
shopMiddleUI.getGoodsInfoV5;确认页还调用getSupplierInfoV5、listPayChannelV5、checkHyProtocolV5、PlayMallUI.getMyPromotion、calcOrderPromotion。 - 页面会重复刷新
getActPrizeList与getUserScore;轮询间隔由工作台自行配置,建议 10-30 秒,写操作后只做一次短轮询。
第一份 HAR 的扫码登录链为:
GET /web/middle/2.6/.../https/...
POST /qrLgn/getQrId
GET /qrLgn/getQrImg?k=<qrId>&appId=5002
POST /qrLgn/tryQrLogin # stage=0 -> stage=1 -> success
POST /web/cookie/verify
成功登录后得到的 UID、Cookie、baseinfo 必须传入同一个 WSS/HTTP 会话。二维码 ID、requestId、context、biztoken、guid、udb_cred、sdid、时间戳和签名均为动态值,报告不固化样本机密值。
参数分类
| 参数 | 类型 | Python 处理 |
|---|---|---|
sid/actId/bActId/moduleId/gid |
业务参数 | 配置项,默认值只对应本次页面 |
uid、游戏账号/角色 |
用户输入或前序响应 | 从当前登录态或绑定响应读取 |
Cookie、baseinfo、WSS session |
Token/Session | HuyaHttpClient 运行时构造并保持 |
qrId/requestId/context/traceId |
随机/请求序号 | 登录和 RPC 运行时生成 |
t/code/sig、biztoken、udb_cred、sdid |
动态签名/认证 | 只转发前序响应或 Cookie;算法未闭合,不重算 |
startTime/endTime/leftNum/isCanExchange |
服务端状态 | 每次查询覆盖本地快照,不写死 |
HTTP 请求保留 User-Agent、Origin、Referer、Content-Type: application/octet-stream 和 Accept-Language;Host、Content-Length、Connection 由 HTTP 库生成。WSS 的 baseinfo query 和二进制 body 由会话客户端生成,不复制浏览器历史头。
4. 业务响应复核
活动信息
getActInfo:status=200,actId=25135,名称“活动+购买任务”,时间戳 1782662400..1790783999,任务模块 20051,外部任务活动 17096,游戏 cjm,组件 3203。17096 与绑定用的 9271 是不同字段,代码中必须分开命名。
奖品列表
getActPrizeList 在 entry 75 的多次响应均返回 29 项、2 个分类:91=限量返场(11 项)和 83=精英专享(18 项)。示例:
| pid | 名称 | 积分 | 分类 |
|---|---|---|---|
| 13161 | 破片手榴弹-粉粉猫爪大礼包 | 3600 | 91 |
| 13163 | 烟雾弹-猫咪绅士大礼包 | 3600 | 91 |
| 13167 | 套装-幸运萌趣趣 | 1980 | 91 |
| 13165 | 套装-奇妙萌趣趣 | 688 | 91 |
| 13169 | 套装-幸福萌趣趣 | 1680 | 91 |
| 12873 | 套装-青涩年华 | 488 | 83 |
| 12867 | 套装-雪山精英 | 600 | 83 |
| 12879 | 套装-浪漫波比 | 1280 | 83 |
| 12865 | 幸运币礼包(大) | 900 | 83 |
完整结构还包含 id/sid/name/score/type/img/sort/frequency/frequencyLimit/num/status/percent/newScore/tags/leftNum/isShowNum/usedNum/goodType/detailImg/detailDesc/whiteUser/commonPrizeId/updateTime/isCanExchange/exchangeStartTime/exchangeEndTime/startTimeSlot/endTimeSlot/isTodayLimit/isUserLimit。库存、排序和可兑换状态在重复轮询中变化,不能硬编码;工作台应以最新响应覆盖快照。
任务与用户进度
getActTaskDetail 返回 6 个任务:
- 购买精英令 *100,奖励 10000 分,SPU
hy-5874270。 - 购买精英令 *10,奖励 1000 分,SPU
hy-5874269。 - 购买精英令 *1,奖励 100 分,SPU
hy-5879346。 - 购买精英徽章,奖励 10 分,SPU
hy-5872824。 - 每天观看和平精英直播 10 分钟,奖励 2 分,任务类型 56。
- 订阅和平精英福利提醒,奖励 5 分,任务类型 68。
getActUserTaskDetail 的每项至少有 actId/taskId/taskStatus/prizeStatus/taskValue/taskCount/prizeCount/subTaskDetail,它是展示任务进度、完成和领取状态的来源。
积分
响应字段顺序为 status/msg/gainScore/usedScore/newGainScore/newUsedScore/score/isOpenExchangeTip。样本值为 4200,4200,4200,4200,0,0;页面逻辑优先使用 max(0, newGainScore-newUsedScore),所以当时可用积分为 0,不能把任意一个累计字段直接当余额。
绑定、记录与地址
- 绑定响应显示游戏“和平精英”,账号平台可为微信或 QQ,
isBindAccount、isBindRole、isNeedActCheck和changeBindTime随状态变化。 getLiveLinkParam返回actId=17096、gameIdList=cjm、livePlatId=huya、动态t/code/sig。样本不足以闭合code/sig算法,不实现猜测签名。confirmBindActAccount样本为status=200,msg=请求成功。getUserPrizeRecords返回 2 条历史记录,字段包括id/name/score/createTime/status/type/isReal/newScore/account/code/commonPrizeType/commonPrizeStatus/orderId/img/goodType/prizeId/recordId/commonPrizeExchangeStatus/commonPrizeId/prizeExtraParam/ymd/commonPrizeMsg。getEntityPrizeFieldMap给出实体奖品字段映射:模块 1 为姓名/手机/地址,模块 38 为 QQ,模块 39 为姓名/手机;getModuleAddress(moduleId=20051)返回status=201,msg=找不到地址。
5. Python 实现边界
仓库现有 core/huya/http_client.py 已实现 WUP/TAF、会话 Cookie、积分、奖品列表、记录、任务、绑定、直播链接和商城方法;新增示例见 scripts/huya_elite_client.py。示例不读取 HAR,运行时从环境变量读取 UID/Cookie,调用顺序为:活动信息/任务/用户任务/绑定/奖品/积分/记录,写操作前重新查询奖品详情。
推荐状态机:
登录态 -> getActInfo/getActTaskDetail
-> checkBind/getActPrizeList/getActUserTaskDetail/getUserScore
-> (用户确认后) getActPrizeDetail -> scoreExchangePrize
-> getUserScore/getActPrizeList/getUserPrizeRecords 回查
兑换必须二次校验 isCanExchange、活动时间、库存、频次、今日/用户限制和可用积分。getActPrizeDetail、scoreExchangePrize 成功响应以及地址写入尚未出现在样本中,客户端应把它们作为显式待补接口,而不是猜测字段。
6. 尚缺证据与补抓清单
当前 HAR 未闭合:getActPrizeDetail 响应、scoreExchangePrize 成功请求/响应、addModuleAddress、createOrderV5、payOrderSubmitV5、支付完成后的订单状态和宝典开通字段。需要重新抓“点击兑换”和“点击开通宝典至支付完成”的完整操作,并保留 Initiator、页面 JavaScript 和同一登录态。