Files
re-xxm/tools/probe_anon.py
bot-ci 8e7ead1669 feat: switch config to JSONC + split secrets.json
Load business config as JSONC (comments + trailing commas) via an
in-repo stripper then stdlib json — no new deps. Default path prefers
config.jsonc, falls back to legacy config.json. Auth write-back targets
only sibling secrets.json so JSONC comments are never wiped; secrets
overlay merges on load. Examples, compose, Docker, docs, favsort and
tools all share the same loader. Phase A only — no DB settings migration.
2026-11-02 12:58:20 +08:00

96 lines
3.5 KiB
Python

# -*- coding: utf-8 -*-
"""只读接口的身份校验探测:对比 完整 cookie / 无 cookie / 去掉身份字段 三种情况。
用法: python tools/probe_anon.py
"""
import json
import os
import sys
import time
import urllib.parse
import urllib.request
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT)
sys.stdout.reconfigure(encoding="utf-8")
from favsort import strip_identity # noqa: E402 与主程序保持同一套剥离规则
BASE = "https://api.bilibili.com"
UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/155.0.0.0 Safari/537.36")
BASE_HEADERS = {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
"dnt": "1",
"origin": "https://www.bilibili.com",
"referer": "https://www.bilibili.com/",
"sec-ch-ua": '"Google Chrome";v="155", "Chromium";v="155", "Not(A:Brand";v="24"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
"user-agent": UA,
}
def get(url, cookie):
headers = dict(BASE_HEADERS)
if cookie is not None:
headers["cookie"] = cookie
req = urllib.request.Request(url, headers=headers)
try:
with urllib.request.urlopen(req, timeout=30) as r:
return json.loads(r.read().decode("utf-8", "replace"))
except Exception as e: # noqa: BLE001
return {"code": "EXC", "message": str(e)[:60]}
def main():
from reaction_board.config import default_config_path, load_config
app = load_config(default_config_path(ROOT), require_auth=False)
full = app.bilibili.read.cookie or app.bilibili.write.cookie
anon = strip_identity(full)
variants = [("完整 cookie", full), ("去掉身份字段", anon), ("完全无 cookie", None)]
folders = [(3700023351, "咻咻满 reaction 合集 (658)"),
(4451053851, "咻咻满-reaction-2025 (167)"),
(85420451, "默认收藏夹 (29)")]
print("=== ids 接口 ===")
for name, ck in variants:
for mid, label in folders:
url = f"{BASE}/x/v3/fav/resource/ids?media_id={mid}&platform=web"
r = get(url, ck)
n = len(r.get("data") or []) if isinstance(r.get("data"), list) else "-"
print(f" [{name:<14}] media={mid:<11} code={r.get('code')!s:<5} "
f"条数={n!s:<5} msg={r.get('message')}")
time.sleep(1.2)
print()
print("=== infos 接口(各取前 3 条)===")
for mid, label in folders:
ids = get(f"{BASE}/x/v3/fav/resource/ids?media_id={mid}&platform=web", full)
arr = ids.get("data") or []
res = ",".join(f"{x['id']}:{x['type']}" for x in arr[:3])
if not res:
print(f" media={mid}: 没有可测资源")
continue
for name, ck in variants:
url = (f"{BASE}/x/v3/fav/resource/infos?resources={urllib.parse.quote(res)}"
f"&platform=web&folder_mid={cfg['mid']}&folder_id={mid}")
r = get(url, ck)
d = r.get("data")
n = len(d) if isinstance(d, list) else "-"
first = (d[0].get("title", "")[:18] if isinstance(d, list) and d else "")
print(f" [{name:<14}] media={mid:<11} code={r.get('code')!s:<5} "
f"返回={n!s:<3} msg={r.get('message')} {first}")
time.sleep(1.2)
print()
if __name__ == "__main__":
main()