"""探测虎牙密码登录在不同 appId/UA 组合下的风控策略。 只走到「触发风控」这一步,打印风控策略(strategy 值 + data URL 路径), 不真正提交滑块/短信/扫码验证,也不写库。 用法: .venv/bin/python scripts/probe_huya_login_scene.py <账号> <明文密码> [--app-id 5002|5008] [--ua desktop|android] 会依次测试多组组合,对比风控返回的是: qr_auth -> 扫码验证(无法自动化) dx_auth -> 短信验证(无法自动化) pt_auth / get3 / slider -> 滑块/点选(可自动化) """ from __future__ import annotations import argparse import sys from core.huya.login import ( APP_ID, APP_ID_MOBILE, APP_UA_MOBILE, DEFAULT_UA, HuyaPasswordLogin, ) def classify_strategy(payload: dict) -> str: """从登录响应里识别风控策略类型。""" data = payload.get("data") or {} strategies = data.get("strategys") or [] if not strategies: return "unknown" urls = [str(s.get("data") or "") for s in strategies] joined = " ".join(urls).lower() strategy_values = [str(s.get("strategy")) for s in strategies] if "qr_auth" in joined or "64" in strategy_values: return "qr_auth(扫码)" if "dx_auth" in joined: return "dx_auth(短信)" if "pt_auth" in joined or "get3" in joined or "slider" in joined: return "pt_auth(滑块)" return f"其他(strategy={','.join(strategy_values)})" def probe(username: str, password: str, app_id: str, ua: str | None = None) -> dict: login = HuyaPasswordLogin(username=username, password=password, app_id=app_id, ua=ua) ua_label = login.ua[:40] print(f"\n=== app_id={app_id} | app_sign={login.app_sign[:8]} | ua={ua_label}... ===") login.prepare_device() login.init_udb_middle() payload = login._password_login_once() return_code = int(payload.get("returnCode") or 0) print(f"returnCode={return_code}") if return_code == 0: print(" → 登录成功(无需验证)") return payload if return_code in (10030, 10039): kind = classify_strategy(payload) print(f" → 风控策略: {kind}") data = payload.get("data") or {} for s in data.get("strategys") or []: print(f" strategy={s.get('strategy')} dataType={s.get('dataType')}") url = str(s.get("data") or "") print(f" data_url={url.split('?')[0]}") return payload print(f" message={payload.get('message')} desc={payload.get('description')}") return payload def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("username") parser.add_argument("password") parser.add_argument("--app-id", default=None, help="只测单个 appId") parser.add_argument("--ua", default=None, choices=["desktop", "android"], help="只测单种 UA") args = parser.parse_args() combos = [] app_ids = [args.app_id] if args.app_id else [APP_ID, APP_ID_MOBILE] for app_id in app_ids: if args.ua == "desktop": combos.append((app_id, DEFAULT_UA)) elif args.ua == "android": combos.append((app_id, APP_UA_MOBILE)) else: # 默认每组都测;5002 也测 Android UA(验证设备画像自洽假设) if app_id == APP_ID_MOBILE: combos.append((app_id, None)) # None -> 自动选 Android UA else: combos.append((app_id, None)) # None -> 桌面 UA combos.append((app_id, APP_UA_MOBILE)) # 强制 Android UA for app_id, ua in combos: try: probe(args.username, args.password, app_id, ua) except Exception as exc: # noqa: BLE001 print(f" !! 探测异常: {type(exc).__name__}: {exc}") return 0 if __name__ == "__main__": sys.exit(main())