虎牙精英宝典
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
# 虎牙精英宝典 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` 完成连接初始化;业务 WUP `requestId` 在同一会话中递增,不能写死 HAR 值。
|
||||
|
||||
## 3. 请求链
|
||||
|
||||
精英宝典 WebSocket entry 75 的可复现顺序如下:
|
||||
|
||||
1. `launch.wsLaunch` -> `mobileui.getConfig`。
|
||||
2. `GameBizUI.getQiWeiRelationByUid`(页面辅助信息)。
|
||||
3. `webActUI.checkUserBindGameAccount(bActId=9271)`,返回和平精英、微信/QQ 平台、角色绑定状态。
|
||||
4. 并行查询:`getActPrizeList(sid=2203)`、`getActInfo(actId=25135)`、`getActTaskDetail(actId=25135)`。
|
||||
5. `getActUserTaskDetail(userId, actId=25135)`、`getUserScore(sid=2203)`。
|
||||
6. 绑定流程:再次检查绑定 -> `huyauserui.getUserProfileBatch` -> `getLiveLinkParam(bActId=9271)` -> `confirmBindActAccount(bActId=9271)` -> 再次检查绑定。
|
||||
7. 记录页:`getUserPrizeRecords(sid=2203)` -> `getEntityPrizeFieldMap` -> `getModuleAddress(moduleId=20051)`。
|
||||
8. 商城前置:`shopMiddleUI.getGoodsInfoV5`;确认页还调用 `getSupplierInfoV5`、`listPayChannelV5`、`checkHyProtocolV5`、`PlayMallUI.getMyPromotion`、`calcOrderPromotion`。
|
||||
9. 页面会重复刷新 `getActPrizeList` 与 `getUserScore`;轮询间隔由工作台自行配置,建议 10-30 秒,写操作后只做一次短轮询。
|
||||
|
||||
第一份 HAR 的扫码登录链为:
|
||||
|
||||
```text
|
||||
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`](../scripts/huya_elite_client.py)。示例不读取 HAR,运行时从环境变量读取 UID/Cookie,调用顺序为:活动信息/任务/用户任务/绑定/奖品/积分/记录,写操作前重新查询奖品详情。
|
||||
|
||||
推荐状态机:
|
||||
|
||||
```text
|
||||
登录态 -> getActInfo/getActTaskDetail
|
||||
-> checkBind/getActPrizeList/getActUserTaskDetail/getUserScore
|
||||
-> (用户确认后) getActPrizeDetail -> scoreExchangePrize
|
||||
-> getUserScore/getActPrizeList/getUserPrizeRecords 回查
|
||||
```
|
||||
|
||||
兑换必须二次校验 `isCanExchange`、活动时间、库存、频次、今日/用户限制和可用积分。`getActPrizeDetail`、`scoreExchangePrize` 成功响应以及地址写入尚未出现在样本中,客户端应把它们作为显式待补接口,而不是猜测字段。
|
||||
|
||||
## 6. 尚缺证据与补抓清单
|
||||
|
||||
当前 HAR 未闭合:`getActPrizeDetail` 响应、`scoreExchangePrize` 成功请求/响应、`addModuleAddress`、`createOrderV5`、`payOrderSubmitV5`、支付完成后的订单状态和宝典开通字段。需要重新抓“点击兑换”和“点击开通宝典至支付完成”的完整操作,并保留 Initiator、页面 JavaScript 和同一登录态。
|
||||
Reference in New Issue
Block a user