{"record":{"id":"cc700f25e916ca28","repo":"jackwener/OpenCLI","slug":"ctrip-attraction-links-rendered-but-parser-did-not","errorCode":null,"errorMessage":"Ctrip attraction links rendered but parser did not find required sight anchors","messagePattern":"Ctrip attraction links rendered but parser did not find required sight anchors","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/attraction.js","lineNumber":63,"sourceCode":"    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        }));\n    },\n});\n","sourceCodeStart":45,"sourceCodeEnd":74,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/attraction.js#L45-L74","documentation":"The DOM extraction ran and returned an array, but it was empty: attraction links were considered rendered by the wait script, yet the parser found no rows with the required sight anchors (name/url in `/sight/<city><cityId>/<id>.html` form). Since a valid city always lists attractions, an empty result is treated as a parsing/consistency failure, not EmptyResultError.","triggerScenarios":"`opencli ctrip attraction <cityId>` where the page shows attraction markup but buildAttractionExtractJs matches zero rows — e.g. links don't carry the expected city-scoped sight URL pattern or lack the anchors the parser requires.","commonSituations":"Partial rendering: links appeared for the wait check but were removed/re-rendered by client JS before extraction; A/B layout variant missing the expected anchors; mismatched cityId between wait and extract scoping; site markup change.","solutions":["Retry the command — transient re-render timing is the most common cause.","Confirm the cityId is correct via `ctrip search`; a wrong-but-renderable id can yield links outside the requested city scope.","Update the adapter if the site changed its sight-link structure.","Inspect the page manually (screenshot/DOM dump) and compare against buildAttractionExtractJs's anchor requirements in clis/ctrip/utils.js."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function getAttractions(cityId, attempts = 2) {\n  try {\n    return await opencli.ctrip.attraction(cityId);\n  } catch (err) {\n    if (err.message.includes('sight anchors') && attempts > 1) {\n      await new Promise(r => setTimeout(r, 3000));\n      return getAttractions(cityId, attempts - 1);\n    }\n    throw err;\n  }\n}","preventionTips":["Retry once with a delay — partial rendering is the usual cause.","Verify the cityId via `ctrip search`; scoped parsing needs the right id.","Update the adapter if sight-link structure changed.","Inspect the page manually if failures are consistent for one city."],"tags":["scraping","empty-result","dom-parsing","ctrip"],"backgroundTag":"scraper-empty-extraction","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}