{"record":{"id":"6dcb03424a52d732","repo":"jackwener/OpenCLI","slug":"ctrip-bus-rows-rendered-but-parser-did-not-find-re","errorCode":null,"errorMessage":"Ctrip bus rows rendered but parser did not find required schedule anchors","messagePattern":"Ctrip bus rows rendered but parser did not find required schedule anchors","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/bus.js","lineNumber":70,"sourceCode":"        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildBusListUrl(fromCity, toCity, date);\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_BUS_JS);\n        if (waitResult === 'captcha') {\n            throw new AuthRequiredError('bus.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 bus page did not render schedule rows (state=${String(waitResult)})`);\n        }\n        const renderedCardCount = await page.evaluate(buildScrollUntilJs('.list-item-parent', limit));\n        const raw = await page.evaluate(buildBusExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Ctrip bus DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            if (Number(renderedCardCount) > 0) {\n                throw new CommandExecutionError('Ctrip bus rows rendered but parser did not find required schedule anchors');\n            }\n            throw new EmptyResultError('ctrip bus', `No coaches for ${fromCity} to ${toCity} on ${date}`);\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            departureTime: r.departureTime,\n            fromStation: r.fromStation,\n            toStation: r.toStation,\n            duration: r.duration,\n            price: r.price,\n            status: r.status,\n            url: searchUrl,\n        }));\n    },\n});\n","sourceCodeStart":52,"sourceCodeEnd":86,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/bus.js#L52-L86","documentation":"When the extract script returns an empty array but the scroll step counted rendered card elements (.list-item-parent), rows exist on screen but the parser failed to find its required schedule anchors in them. The CLI throws CommandExecutionError because this is a parser/DOM mismatch, not an absence of data.","triggerScenarios":"`clis ctrip bus` where buildScrollUntilJs('.list-item-parent', limit) reports renderedCardCount > 0 but buildBusExtractJs() returns [] because the required per-row anchor fields are missing or renamed in the DOM.","commonSituations":"Ctrip changing internal row markup (anchors) while keeping .list-item-parent wrappers; partially loaded rows (images/meta not hydrated); lazy-rendered cards with placeholder content at scroll time.","solutions":["Rerun after a longer settle delay so row content fully hydrates before extraction","Update buildBusExtractJs to match the current row anchor selectors","Report/update the CLI if Ctrip changed their markup permanently"],"exampleFix":"null","handlingStrategy":"fallback","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  rows = await ctripBusList({ from, to, date });\n} catch (e) {\n  if (e instanceof CommandExecutionError && e.message.includes('schedule anchors')) {\n    // fallback: retry once after letting the page fully hydrate, then escalate\n    await sleep(5000);\n    try { rows = await ctripBusList({ from, to, date }); }\n    catch { console.error('Parser anchors stale — update buildBusExtractJs selectors'); rows = []; }\n  } else { throw e; }\n}","preventionTips":["Allow extra settle time after scrolling so lazy-rendered rows hydrate before extraction","Track ctrip markup changes affecting row anchors even when wrapper classes stay the same","Distinguish this error (parser mismatch) from EmptyResultError (no data) in your handling code","Add a smoke test comparing rendered card count to extracted row count"],"tags":["dom-parsing","ctrip","scraping","selector-mismatch"],"backgroundTag":"dom-extraction-malformed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}