{"record":{"id":"ee0d4503b4ef1e4f","repo":"jackwener/OpenCLI","slug":"ctrip-is-asking-for-a-captcha-complete-it-in-your-ee0d45","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/tour.js","lineNumber":47,"sourceCode":"        { name: 'destination', required: true, positional: true, help: 'Destination keyword (e.g. 北京 / 三亚 / 马尔代夫)' },\n        { name: 'limit', default: 20, help: 'Number of packages (1-50)' },\n    ],\n    columns: [\n        'rank',\n        'title', 'subtitle',\n        'tags', 'score', 'sold', 'reviews',\n        'price',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const destination = parsePlaceName('destination', kwargs.destination);\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildTourListUrl(destination);\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_VACATIONS_JS);\n        if (waitResult === 'captcha') {\n            throw new AuthRequiredError('vacations.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');\n        }\n        if (waitResult === 'empty') {\n            throw new EmptyResultError('ctrip tour', `No tour packages for \"${destination}\"`);\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Ctrip tour page did not render package cards (state=${String(waitResult)})`);\n        }\n        const raw = await page.evaluate(buildVacationsExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Ctrip tour DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            throw new CommandExecutionError('Ctrip tour cards rendered but parser did not find required package anchors');\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            title: r.title,\n            subtitle: r.subtitle,","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/tour.js#L29-L65","documentation":"An AuthRequiredError raised by `ctrip tour` when WAIT_FOR_VACATIONS_JS detects that vacations.ctrip.com is serving a captcha challenge instead of search results. The library's cookie-based browser session is not trusted by Ctrip's anti-bot system, so it requires the user to solve the captcha interactively in their own browser session and retry.","triggerScenarios":"Running `opencli ctrip tour <destination>` when page.evaluate(WAIT_FOR_VACATIONS_JS) returns 'captcha' — Ctrip's risk control intercepted the headless/cookie-authenticated request after page.goto(buildTourListUrl(destination)).","commonSituations":"Expired or missing login cookies (Strategy.COOKIE); running from a datacenter/VPN IP flagged by Ctrip; too many rapid successive scrapes triggering rate limiting; headless browser fingerprint detection.","solutions":["Open vacations.ctrip.com in your normal browser, solve the captcha, and refresh your session cookies used by the CLI","Re-export fresh cookies after logging in again on ctrip.com","Slow down request frequency and add delays between commands","Switch off VPN/proxy or use a residential IP","Retry the command after completing the captcha"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// before running: confirm cookies are fresh\nif (!fs.existsSync(cookieFile) || isOlderThan(cookieFile, DAYS_7)) {\n  console.error('Refresh your ctrip.com session cookies first');\n  process.exit(1);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const tours = await runCli('ctrip', 'tour', dest);\n} catch (e) {\n  if (e.name === 'AuthRequiredError') {\n    console.error('Solve the captcha at vacations.ctrip.com in your browser, refresh cookies, then retry');\n  } else throw e;\n}","preventionTips":["Solve captchas in your normal browser session and re-export cookies regularly","Avoid datacenter IPs/VPNs that Ctrip risk control flags","Throttle request frequency; add delays between scrapes","Use a non-headless or well-configured browser profile to reduce bot detection"],"tags":["auth","captcha","anti-bot","ctrip"],"backgroundTag":"captcha-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}