真实浏览器抓包与匿名设备态协议生成器

This commit is contained in:
yml2213
2026-09-01 19:17:36 +08:00
parent 48c37bb8d7
commit 8447ca82ed
3 changed files with 901 additions and 0 deletions
+177
View File
@@ -0,0 +1,177 @@
"""虎牙网页匿名设备态协议生成器(纯 HTTPmiddle + anonymousLogin)。
生成 4 个网页设备态字段(来源见 docs/HUYA_COOKIE合并审计与来源矩阵.md):
- ``udb_deviceid`` <- GET /web/middle/2.4/{rand8}/https/{hex32} 的 Set-Cookie
- ``udb_guiddata`` <- middle URL 第三段 hex32(客户端自选,服务端不校验)
- ``udb_anobiztoken``<- POST /web/anonymousLogin 响应 data.biztoken344 位)
- ``udb_anouid`` <- anonymousLogin 响应 data.uid
用法::
python -m core.huya.anon_device # 打印 4 字段 JSON
python -m core.huya.anon_device --json # 同上,紧凑 JSON(供脚本消费)
注意: 200 / returnCode=0 只证明接口受理,不证明风控认可这些值的真实性。
``guid`` / ``_qimei_uuid42`` / ``__yamid_new`` / ``game_did`` 仍无服务端
签发接口,本模块不生成、不伪造它们。
"""
from __future__ import annotations
import argparse
import json
import random
import re
import secrets
import sys
from collections.abc import Mapping
import requests
from loguru import logger
MIDDLE_URL = "https://udblgn.huya.com/web/middle/2.4/{rand8}/https/{guiddata}"
ANON_LOGIN_URL = "https://udblgn.huya.com/web/anonymousLogin"
DESKTOP_UA = (
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36"
)
UDBN_DEVICEID_RE = re.compile(r"udb_deviceid=([^;]+)")
class AnonymousDeviceError(RuntimeError):
"""匿名设备态获取失败。"""
def _new_session(*, proxies: Mapping[str, str] | None = None) -> requests.Session:
session = requests.Session()
session.trust_env = False
if proxies:
session.proxies.update(dict(proxies))
return session
def _parse_set_cookie_deviceid(set_cookie: str) -> str:
match = UDBN_DEVICEID_RE.search(set_cookie or "")
if not match or not re.fullmatch(r"w_\d{19}", match.group(1)):
raise AnonymousDeviceError("middle 响应未下发合法 udb_deviceid")
return match.group(1)
def fetch_anonymous_device_state(
*,
proxies: Mapping[str, str] | None = None,
timeout: float = 15.0,
session: requests.Session | None = None,
) -> dict[str, str]:
"""换取匿名设备态四字段:udb_deviceid / udb_guiddata / udb_anobiztoken / udb_anouid。
与网页 SDK 相同的两步:middle 引导页签发 deviceidanonymousLogin 换取
biztoken/uid。所有参数客户端随机生成,无需任何既有 Cookie。
"""
own_session = session is None
s = session or _new_session(proxies=proxies)
try:
guiddata = secrets.token_hex(16)
rand8 = str(random.randint(10_000_000, 99_999_999))
middle_url = MIDDLE_URL.format(rand8=rand8, guiddata=guiddata)
# 1) middle:签发 udb_deviceid
resp = s.get(
middle_url,
headers={"User-Agent": DESKTOP_UA, "Referer": "https://www.huya.com/"},
timeout=timeout,
allow_redirects=False,
)
if resp.status_code != 200:
raise AnonymousDeviceError(f"middle 返回 {resp.status_code}")
deviceid = _parse_set_cookie_deviceid(resp.headers.get("Set-Cookie", ""))
# 2) anonymousLogin:发放匿名 uid + biztoken(必须带 middle Referer
context = (
"WB-"
+ secrets.token_hex(16)
+ "-" + secrets.token_hex(16)
+ "-" + secrets.token_hex(16)
)
payload = {
"uri": "10013",
"version": "2.4",
"context": context,
"appId": 5002,
"sdid": "csid_" + secrets.token_hex(16),
"lcid": 2052,
"byPass": 3,
"requestId": random.randint(10_000_000, 99_999_999),
"authId": "",
"data": {"domainList": ""},
}
anon = s.post(
ANON_LOGIN_URL,
headers={
"User-Agent": DESKTOP_UA,
"Referer": middle_url,
"Content-Type": "application/json;charset=UTF-8",
},
data=json.dumps(payload),
timeout=timeout,
allow_redirects=False,
)
if anon.status_code != 200:
raise AnonymousDeviceError(f"anonymousLogin 返回 {anon.status_code}")
try:
body = anon.json()
except ValueError as exc:
raise AnonymousDeviceError(
f"anonymousLogin 响应非 JSON: {anon.text[:80]!r}"
) from exc
if body.get("returnCode") != 0:
raise AnonymousDeviceError(
f"anonymousLogin returnCode={body.get('returnCode')} "
f"message={body.get('message')!r}"
)
data = body.get("data") or {}
anouid = str(data.get("uid") or "")
biztoken = str(data.get("biztoken") or "")
if not anouid or not biztoken:
raise AnonymousDeviceError("anonymousLogin 响应缺少 uid/biztoken")
if not 300 <= len(biztoken) <= 400:
logger.warning("[huya-anon] biztoken 长度异常: {}", len(biztoken))
logger.info(
"[huya-anon] 匿名设备态 OK: deviceid={}... guiddata={}... "
"anouid={} biztoken={}...",
deviceid[:14], guiddata[:8], anouid, biztoken[:10],
)
return {
"udb_deviceid": deviceid,
"udb_guiddata": guiddata,
"udb_anobiztoken": biztoken,
"udb_anouid": anouid,
}
finally:
if own_session:
s.close()
def main() -> int:
ap = argparse.ArgumentParser(description="虎牙匿名设备态四字段生成(纯协议)")
ap.add_argument("--json", action="store_true", help="输出紧凑 JSON")
args = ap.parse_args()
try:
state = fetch_anonymous_device_state()
except AnonymousDeviceError as exc:
print(f"{exc}", file=sys.stderr)
return 2
if args.json:
print(json.dumps(state, ensure_ascii=False))
else:
for key, value in state.items():
print(f"{key} = {value}")
print("\n4/7 字段;guid/_qimei_uuid42/__yamid_new/game_did 无服务端签发,不生成)")
return 0
if __name__ == "__main__":
raise SystemExit(main())