{"record":{"id":"8bde25949f35aa95","repo":"jackwener/OpenCLI","slug":"xueqiu-com-8bde25","errorCode":null,"errorMessage":"xueqiu.com","messagePattern":"xueqiu\\.com","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/xueqiu/hot-stock.js","lineNumber":21,"sourceCode":"import { fetchXueqiuJson } from './utils.js';\ncli({\n    site: 'xueqiu',\n    name: 'hot-stock',\n    access: 'read',\n    description: '获取雪球热门股票榜',\n    domain: 'xueqiu.com',\n    browser: true,\n    args: [\n        { name: 'limit', type: 'int', default: 20, help: '返回数量，默认 20，最大 50' },\n        { name: 'type', default: '10', help: '榜单类型 10=人气榜(默认) 12=关注榜' },\n    ],\n    columns: ['rank', 'symbol', 'name', 'price', 'changePercent', 'heat'],\n    func: async (page, kwargs) => {\n        await page.goto('https://xueqiu.com');\n        const url = `https://stock.xueqiu.com/v5/stock/hot_stock/list.json?size=${kwargs.limit}&type=${kwargs.type}`;\n        const d = await fetchXueqiuJson(page, url);\n        if (!d.data?.items)\n            throw new AuthRequiredError('xueqiu.com');\n        return (d.data.items || []).map((s, i) => ({\n            rank: i + 1,\n            symbol: s.symbol,\n            name: s.name,\n            price: s.current,\n            changePercent: s.percent != null ? s.percent.toFixed(2) + '%' : null,\n            heat: s.value,\n            url: 'https://xueqiu.com/S/' + s.symbol,\n        }));\n    },\n});\n","sourceCodeStart":3,"sourceCodeEnd":33,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xueqiu/hot-stock.js#L3-L33","documentation":"The xueqiu hot-stock command fetches the hot-stock list from stock.xueqiu.com/v5/stock/hot_stock/list.json after priming the session at xueqiu.com. If the response lacks data.items, it throws AuthRequiredError('xueqiu.com') because the hot-stock endpoint also requires a logged-in session. The error signals the user must authenticate before this data is available.","triggerScenarios":"Invoking the hot-stock command with an unauthenticated or expired xueqiu session so the API returns an error payload without data.items; also when xueqiu returns success:false for the request.","commonSituations":"Session cookies expired between runs; user cleared browser data; running in a fresh container/browser without a logged-in profile; xueqiu anti-bot measures logged the session out.","solutions":["Log in to xueqiu.com in the browser used by the CLI, then re-run the command","Reuse a persisted logged-in browser profile instead of a fresh one","Inspect the API response for xueqiu auth error codes to confirm the session is invalid","Retry later if xueqiu is throttling the session"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const d = await fetchXueqiuJson(page, `https://stock.xueqiu.com/v5/stock/hot_stock/list.json?size=${limit}&type=${type}`);\nif (!d || d.error_code || !d.data?.items) {\n  throw new Error('Hot-stock list unavailable — xueqiu session likely unauthenticated (log in to xueqiu.com).');\n}","typeGuard":"function hasHotStocks(d) {\n  return Boolean(d && typeof d === 'object' && d.data && Array.isArray(d.data.items));\n}","tryCatchPattern":"try {\n  const hot = await xueqiuHotStock({ limit: 20, type: '10' });\n} catch (e) {\n  if (e instanceof AuthRequiredError || /xueqiu\\.com/.test(e.message)) {\n    console.error('Session expired: log in to xueqiu.com and retry.');\n  } else throw e;\n}","preventionTips":["Verify xueqiu login status before batch runs (e.g. fetch a cheap authed endpoint first)","Persist cookies/profile so sessions survive restarts","Detect xueqiu error codes in the raw response to distinguish auth vs rate-limit issues","Re-login proactively when you see repeated AuthRequiredError"],"tags":["auth","scraping","xueqiu","session-expired"],"backgroundTag":"auth-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}