xueqiu: 匿名 token 可从 /hq 取得,首页兜底已失效导致 400016;过期的 xueqiu_cookie 还会静默屏蔽兜底
概要
v1.5.0 的 xueqiu channel 在我机器上稳定报 HTTP Error 400(error_code: 400016)。排查下来有两个独立的 bug,都不需要真实登录态就能修复——匿名 token 是拿得到的,只是取 token 的页面选错了。
这条与已关闭的 #219 结论相反:#219 的修复方向是「必须复用浏览器登录 cookie」,但实际上公开行情接口只要一个匿名 xq_a_token 就够。
环境:Agent Reach v1.5.0,WSL2 (Ubuntu),Python 3.14,无代理。
Bug 1:_XUEQIU_HOME 指向的首页已不再下发 xq_a_token
channels/xueqiu.py 的匿名兜底访问 https://xueqiu.com 来取会话 cookie,但雪球现在首页只下发 acw_tc,不再下发 xq_a_token,于是后续 quote 调用必然 400016。
https://xueqiu.com/hq(以及 /about)仍会下发完整的匿名 token 组。
复现(Mac UA 与 Windows UA 结果一致):
import http.cookiejar, urllib.request
UA = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
for page in ["https://xueqiu.com/", "https://xueqiu.com/hq"]:
jar = http.cookiejar.CookieJar()
op = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
op.open(urllib.request.Request(page, headers={"User-Agent": UA}), timeout=15)
print(page, [c.name for c in jar])
输出:
https://xueqiu.com/ ['acw_tc']
https://xueqiu.com/hq ['acw_tc', 'xq_a_token', 'xqat', 'xq_r_token', 'xq_id_token', 'cookiesu', 'u']
用首页的 cookie 调 quote:
HTTP Error 400
{"error_description":"遇到错误,请刷新页面或者重新登录帐号后再试",
"error_uri":"/v5/stock/quote.json","error_data":null,"error_code":"400016"}
修复:把常量换成会下发 token 的页面即可,一行:
-_XUEQIU_HOME = "https://xueqiu.com"
+_XUEQIU_HOME = "https://xueqiu.com/hq" # 首页已不再下发 xq_a_token
改完后 get_stock_quote / search_stock / get_hot_stocks / get_hot_posts 四个方法在完全匿名(config 里没有任何 xueqiu cookie)的情况下全部返回真实数据,doctor 变成 status: ok。建议顺带把 backends = ["Xueqiu API (需要登录 Cookie)"] 的文案改掉——这几个接口并不需要登录态。
Bug 2:config.yaml 里过期的 xueqiu_cookie 会静默屏蔽匿名兜底,且没有清除入口
_ensure_cookies() 的优先级是「配置文件 cookie → 首页兜底」,一旦 ~/.agent-reach/config.yaml 里存过一个 xueqiu_cookie,即使它已经过期,_load_cookies_from_config() 也会返回 True,兜底永远不执行。
我这台机器上就是这个状态:之前某次 configure --from-browser 存下的 xq_a_token 早已失效,于是即便修好了 Bug 1,doctor 仍然 400016,直到手工把这行从 config.yaml 里删掉才恢复。
而 agent-reach configure 的 positional choices 是 {proxy, github-token, groq-key, openai-key, twitter-cookies, youtube-cookies, xhs-cookies},没有 xueqiu 项,用户没有受支持的办法清除或改写这个 key,只能手改 YAML。
check() 的报错文案也只建议「重新 configure --from-browser」,完全没提到「你存的 cookie 可能已经过期并正在屏蔽兜底」,把人往错误方向引(这大概也是 #219 当时被误判成"必须登录"的原因之一)。
建议:
- 配置里的 cookie 失败时降级到匿名兜底,而不是直接抛错——
_load_cookies_from_config成功注入 ≠ cookie 有效。 check()识别400016,明确提示「已保存的 xueqiu_cookie 可能已过期,可删除~/.agent-reach/config.yaml中的xueqiu_cookie后重试」。configure增加xueqiu-cookiepositional(或一个通用的--unset <key>),让用户能清除失效凭据。
验证
打完 Bug 1 的补丁 + 清掉过期 cookie 后(匿名,无登录态):
doctor: xueqiu status=ok, active_backend="Xueqiu API"
quote: 中国平安 57.23 +2.53%
search: SH600036 招商银行 / 03968 招商银行 / CIHKY 招商银行ADR
hot_stocks: 中际旭创 / 招商银行 / 古井贡酒
hot_posts: 正常返回作者与正文
Source: Panniantong/Agent-Reach