{"record":{"id":"65f8497c3a06474f","repo":"jackwener/OpenCLI","slug":"ctrip-is-asking-for-a-captcha-complete-it-in-your-65f849","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/cruise.js","lineNumber":52,"sourceCode":"        { name: 'port', required: true, positional: true, help: 'Departure cruise port name (e.g. 上海 / 威尼斯 / 罗马)' },\n        { name: 'limit', default: 20, help: 'Number of cruises (1-50)' },\n    ],\n    columns: [\n        'rank',\n        'title', 'star',\n        'boarding', 'sailingDate',\n        'tags', 'price',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const port = parsePlaceName('port', kwargs.port);\n        const limit = parseListLimit(kwargs.limit);\n\n        const indexUrl = buildCruiseSearchUrl(PORT_INDEX_CODE);\n        await page.goto(indexUrl);\n        const indexWait = await page.evaluate(WAIT_FOR_CRUISE_JS);\n        if (indexWait === 'captcha') {\n            throw new AuthRequiredError('cruise.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');\n        }\n        if (indexWait !== 'content') {\n            throw new CommandExecutionError(`Ctrip cruise page did not render (state=${String(indexWait)})`);\n        }\n        const portCode = await page.evaluate(buildCruisePortLookupJs(port));\n        if (!portCode) {\n            throw new EmptyResultError('ctrip cruise', `No cruise departure port matching \"${port}\" (try a listed sea-cruise port like 上海 / 威尼斯 / 罗马)`);\n        }\n\n        let searchUrl = indexUrl;\n        if (portCode !== PORT_INDEX_CODE) {\n            searchUrl = buildCruiseSearchUrl(portCode);\n            await page.goto(searchUrl);\n            const portWait = await page.evaluate(WAIT_FOR_CRUISE_JS);\n            if (portWait === 'captcha') {\n                throw new AuthRequiredError('cruise.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');\n            }\n            if (portWait === 'empty') {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/cruise.js#L34-L70","documentation":"The cruise command navigates to the Ctrip cruise index and waits via WAIT_FOR_CRUISE_JS. If the returned state is 'captcha', Ctrip's anti-bot protection is intercepting cruise.ctrip.com, and the CLI throws AuthRequiredError telling the user to solve the captcha in their own browser session and retry.","triggerScenarios":"`clis ctrip cruise` where page.evaluate(WAIT_FOR_CRUISE_JS) on buildCruiseSearchUrl(PORT_INDEX_CODE) returns 'captcha' — the session or IP was flagged by Ctrip's WAF.","commonSituations":"High-frequency cruise queries triggering rate limits; headless/automation-flagged browser; shared datacenter IP with poor reputation; expired session cookies prompting re-verification.","solutions":["Open the same browser session, complete the captcha on cruise.ctrip.com, then rerun","Use a persistent browser profile with established Ctrip cookies","Throttle query frequency and add jitter/delays between runs","Try a different network/IP if flagged persistently"],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  cruises = await ctripCruiseList({ port });\n} catch (e) {\n  if (e instanceof AuthRequiredError && e.message.includes('captcha')) {\n    await promptManualCaptchaResolution('cruise.ctrip.com');\n    cruises = await ctripCruiseList({ port });\n  } else {\n    throw e;\n  }\n}","preventionTips":["Reuse a persistent browser session with prior human activity on ctrip","Throttle cruise queries; avoid rapid successive runs from the same IP","Alert a human on AuthRequiredError instead of automated retries","Prefer residential networks over datacenter IPs for ctrip access"],"tags":["captcha","ctrip","anti-bot","auth"],"backgroundTag":"captcha-challenge-blocked","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}