{"record":{"id":"42307959a72fd8c0","repo":"jackwener/OpenCLI","slug":"error-423079","errorCode":null,"errorMessage":"触发了验证码，请先在浏览器中完成滑块验证","messagePattern":"触发了验证码，请先在浏览器中完成滑块验证","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"warning","filePath":"clis/ke/utils.js","lineNumber":57,"sourceCode":"    })()\n  `);\n    if (!result) {\n        return { href: '', title: '', body_text: '' };\n    }\n    return {\n        href: cleanText(result.href),\n        title: cleanText(result.title),\n        body_text: cleanText(result.body_text),\n    };\n}\n\nexport function assertNotBlocked(state) {\n    const { href, title, body_text } = state;\n    if (href.includes('hip.ke.com/captcha') || href.includes('/captcha')) {\n        throw new AuthRequiredError('ke.com', '触发了验证码，请先在浏览器中完成验证');\n    }\n    if (CAPTCHA_TEXT_PATTERNS.some(p => title.includes(p) || body_text.includes(p))) {\n        throw new AuthRequiredError('ke.com', '触发了验证码，请先在浏览器中完成滑块验证');\n    }\n    if (LOGIN_TEXT_PATTERNS.some(p => title.includes(p))) {\n        throw new AuthRequiredError('ke.com', '未登录，请先在浏览器中登录贝壳找房');\n    }\n}\n\nexport async function gotoKe(page, url) {\n    await page.goto(url, { settleMs: 2500 });\n    await page.wait(2);\n    const state = await readPageState(page);\n    assertNotBlocked(state);\n    return state;\n}\n\n/**\n * Fetch a ke.com JSON API from inside the browser context (credentials included).\n */\nexport async function fetchKeJson(page, url) {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ke/utils.js#L39-L75","documentation":"assertNotBlocked scans the page title and first 2000 chars of body text for captcha phrases (请拖动下方滑块完成验证, 验证码, 安全验证, etc.). When one appears — even if the URL doesn't contain /captcha — it throws AuthRequiredError asking the user to complete the slider/captcha verification in the browser. This catches inline captcha overlays embedded in otherwise-normal pages.","triggerScenarios":"gotoKe lands on a page whose DOM contains a slider-captcha widget or security-verification text (risk control interstitial); Beike injects a滑块 challenge after suspicious request patterns.","commonSituations":"Aggressive scraping frequency; shared IP previously flagged; new session with no browsing history hitting sensitive endpoints (e.g. house detail pages).","solutions":["Complete the slider captcha manually in the browser session","Reduce request rate and add randomized delays between commands","Log in with a valid lianjia_token to lower risk-control sensitivity","Retry from a residential IP / different network"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const state = await readPageState(page);\nconst captchaWords = ['验证码','安全验证','滑动验证','请按住滑块','请拖动下方滑块完成验证','访问验证'];\nif (captchaWords.some(w => state.title.includes(w) || state.body_text.includes(w))) {\n  console.log('Slider captcha detected — complete it in the browser');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await gotoKe(page, url);\n} catch (e) {\n  if (e instanceof AuthRequiredError && e.message.includes('滑块')) {\n    console.error('Complete the slider verification in the browser window, then re-run.');\n    process.exitCode = 2;\n    return;\n  }\n  throw e;\n}","preventionTips":["Add human-like pacing and randomized delays between navigations","Warm up sessions with light browsing before hitting data-heavy pages","Solve captchas immediately when prompted; repeated challenges escalate risk control","Rotate to a cleaner IP if captchas recur within a single run"],"tags":["captcha","anti-bot","slider","ke"],"backgroundTag":"captcha-challenge","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}