{"record":{"id":"174e772c35c32729","repo":"jackwener/OpenCLI","slug":"ctrip-is-asking-for-a-captcha-complete-it-in-your","errorCode":null,"errorMessage":"Ctrip is asking for a captcha; complete it in your browser session and retry","messagePattern":"Ctrip is asking for a captcha; complete it in your browser session and retry","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/attraction.js","lineNumber":53,"sourceCode":"    args: [\n        { name: 'city', required: true, positional: true, help: 'Numeric Ctrip city id (from `ctrip search`, e.g. 1 for 北京)' },\n        { name: 'limit', default: 20, help: 'Number of attractions (1-50)' },\n    ],\n    columns: [\n        'rank',\n        'name',\n        'rating', 'reviews',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const cityId = parseCityId(kwargs.city);\n        const limit = parseListLimit(kwargs.limit);\n\n        const placeUrl = buildAttractionPlaceUrl(cityId);\n        await page.goto(placeUrl);\n        const waitResult = await page.evaluate(buildWaitForAttractionsJs(cityId));\n        if (waitResult === 'captcha') {\n            throw new AuthRequiredError('you.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Ctrip place page did not render attraction links for city id ${cityId} (state=${String(waitResult)}); check the city id`);\n        }\n        const raw = await page.evaluate(buildAttractionExtractJs(cityId));\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Ctrip attraction DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            throw new CommandExecutionError('Ctrip attraction links rendered but parser did not find required sight anchors');\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            name: r.name,\n            rating: r.rating,\n            reviews: r.reviews,\n            url: r.url,\n        }));","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/attraction.js#L35-L71","documentation":"The ctrip attraction command navigates to the you.ctrip.com place page and runs a wait script via page.evaluate; if the page state resolves to 'captcha', it throws AuthRequiredError because Ctrip is presenting an anti-bot challenge instead of rendering content. The library requires an authenticated browser session (Strategy.COOKIE) and asks you to solve the captcha in that session before retrying.","triggerScenarios":"Running `opencli ctrip attraction <cityId>` when the headless/cookie-based browser session triggers Ctrip's bot detection: suspicious traffic patterns, missing/expired cookies, datacenter IP, or too-frequent scraping.","commonSituations":"Running many attraction queries in a row; using a VPN/cloud server IP; session cookies expiring so Ctrip no longer trusts the client; aggressive polling from automation.","solutions":["Open the browser session used by the CLI (the same cookie profile), visit you.ctrip.com manually, and complete the captcha.","Log in via the site's auth command (`ctrip login`) so a fresh, trusted login_uid cookie exists, then retry.","Slow down: add delays between attraction queries and avoid bulk scraping.","Retry from a residential/different IP if you are on a datacenter address."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// ensure a logged-in session exists before scraping commands\nconst who = await opencli.ctrip.whoami().catch(() => null);\nif (!who) await opencli.ctrip.login();","typeGuard":null,"tryCatchPattern":"try {\n  const rows = await opencli.ctrip.attraction(cityId);\n} catch (err) {\n  if (err.name === 'AuthRequiredError' && /captcha/i.test(err.message)) {\n    // prompt the user to open the browser session and solve the captcha, then retry\n  }\n  throw err;\n}","preventionTips":["Keep a logged-in Ctrip session (ctrip login) so bot detection trusts the client.","Throttle attraction queries; avoid bulk scraping runs.","Don't automate from datacenter/VPN IPs when possible.","Handle AuthRequiredError by pausing for human captcha completion rather than hammering retries."],"tags":["captcha","anti-bot","auth-required","ctrip","scraping"],"backgroundTag":"captcha-challenge-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}