{"record":{"id":"ea6bbfbbd1d83ab2","repo":"jackwener/OpenCLI","slug":"ctrip-tour-cards-rendered-but-parser-did-not-find","errorCode":null,"errorMessage":"Ctrip tour cards rendered but parser did not find required package anchors","messagePattern":"Ctrip tour cards rendered but parser did not find required package anchors","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/tour.js","lineNumber":60,"sourceCode":"\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,\n            tags: r.tags,\n            score: r.score,\n            sold: r.sold,\n            reviews: r.reviews,\n            price: r.price,\n            url: searchUrl,\n        }));\n    },\n});\n","sourceCodeStart":42,"sourceCodeEnd":75,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/tour.js#L42-L75","documentation":"A CommandExecutionError raised by `ctrip tour` when the extraction returned a well-formed but empty array: tour cards rendered in the DOM, yet the parser matched no elements against its required package anchors (.list_product_item based selectors). This signals a markup/parser mismatch rather than a load failure or genuinely empty results.","triggerScenarios":"Running `opencli ctrip tour <destination>` where the page visually shows tour cards but buildVacationsExtractJs() finds no anchor elements — typically after a Ctrip class rename, an A/B markup variant, or results nested in an iframe/shadow root the extractor does not reach.","commonSituations":"Ctrip front-end redesign changing card class names; regional Ctrip versions with different DOM; A/B test variants; results rendered via a different template for certain destinations.","solutions":["Check in a browser whether .list_product_item still exists on the tour results page","Update the CLI to a version whose extractor matches current markup","Try a popular destination (e.g. 北京) to rule out keyword-specific templates","Inspect for iframes/shadow DOM and extend the extractor accordingly","Patch the selectors in buildVacationsExtractJs (clis/ctrip/utils.js) to the new classes"],"exampleFix":"// before\nif (raw.length === 0) throw new CommandExecutionError('parser did not find required package anchors');\n// after\nif (raw.length === 0) {\n  const alt = await page.evaluate(fallbackTourExtractJs()); // updated selectors\n  if (!alt.length) throw new CommandExecutionError('parser did not find required package anchors');\n  return alt.slice(0, limit);\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const tours = await runCli('ctrip', 'tour', dest);\n} catch (e) {\n  if (e.name === 'CommandExecutionError' && e.message.includes('package anchors')) {\n    tours = await runCli('ctrip', 'package', dest); // alternate tab / flag selector drift\n  } else throw e;\n}","preventionTips":["Verify .list_product_item still exists on the tour page when errors begin","Update the CLI promptly after Ctrip redesigns","Test with a popular destination to separate parser drift from data issues","Check for iframes/shadow DOM when selectors silently stop matching"],"tags":["dom-extraction","selector-mismatch","scraping","ctrip"],"backgroundTag":"selector-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}