{"record":{"id":"7e02a28249bb313d","repo":"jackwener/OpenCLI","slug":"dianping-citylist-did-not-render-any-city-anchors","errorCode":null,"errorMessage":"dianping citylist did not render any city anchors; cannot resolve Chinese city names","messagePattern":"dianping citylist did not render any city anchors; cannot resolve Chinese city names","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/dianping/cityResolver.js","lineNumber":114,"sourceCode":"        );\n    }\n\n    RESOLVE_CACHE.set(lowered, cityId);\n    RESOLVE_CACHE.set(pinyin, cityId);\n    if (CHINESE_RE.test(raw)) RESOLVE_CACHE.set(raw, cityId);\n    return cityId;\n}\n\n/**\n * Read https://www.dianping.com/citylist and return a Chinese-name → pinyin\n * slug map for every city link present on the page. Used when the user\n * supplied a Chinese name that isn't in the static map.\n */\nasync function lookupPinyinFromCitylist(page, chineseName) {\n    await page.goto('https://www.dianping.com/citylist');\n    const map = await page.evaluate(`(${buildCitylistMap.toString()})()`);\n    if (!map || typeof map !== 'object' || Object.keys(map).length === 0) {\n        throw new CommandExecutionError(\n            'dianping citylist did not render any city anchors; cannot resolve Chinese city names',\n        );\n    }\n    if (map && typeof map === 'object' && map[chineseName]) {\n        return String(map[chineseName]).toLowerCase();\n    }\n    return null;\n}\n\n/**\n * Pure DOM extractor for /citylist. Walks every anchor on the page and\n * keeps the ones whose href matches the per-city slug shape and whose\n * text is a pure-Chinese label. Defined at module scope so the same code\n * can be exercised from JSDOM tests via toString() injection.\n */\nexport function buildCitylistMap() {\n    const map = {};\n    const anchors = document.querySelectorAll('a');","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/dianping/cityResolver.js#L96-L132","documentation":"CommandExecutionError from lookupPinyinFromCitylist when https://www.dianping.com/citylist loads but the extracted map of city-name → pinyin anchors is empty or not an object. The library cannot translate Chinese city names to pinyin slugs without this page, so resolution of Chinese names fails hard. Typically the page was blocked, challenge-walled, or its markup changed.","triggerScenarios":"resolveCityIdAsync receives a Chinese name not in the static CITY_ID map, calls lookupPinyinFromCitylist, which navigates to /citylist and runs buildCitylistMap via page.evaluate — returning {} or null because no city anchors were found in the DOM.","commonSituations":"Dianping serving an anti-bot/captcha page at /citylist; page evaluated before content rendered; Dianping redesigned citylist so buildCitylistMap's selectors match nothing; network/proxy failure yielding an error page that still 'loads'.","solutions":["Retry — if it was a transient render/timing issue, a second attempt may render the anchors (add an explicit wait for city anchor selectors before evaluate).","Avoid the online path: pass a pinyin slug or numeric cityId for --city instead of a Chinese name.","Open dianping.com/citylist in the automation browser and screenshot the page to see if a captcha/verify wall is shown; solve it or slow down request rate.","If markup changed, update buildCitylistMap in cityResolver.js to match the new anchor structure."],"exampleFix":"// before\nawait page.goto('https://www.dianping.com/citylist');\nconst map = await page.evaluate(`(${buildCitylistMap.toString()})()`);\n// after\nawait page.goto('https://www.dianping.com/citylist');\nawait page.waitForSelector('a[href*=\".dianping.com\"]', { timeout: 10000 }).catch(() => null);\nconst map = await page.evaluate(`(${buildCitylistMap.toString()})()`);","handlingStrategy":"fallback","validationCode":"// pre-check citylist renderability\nawait page.goto('https://www.dianping.com/citylist');\nconst n = await page.evaluate(`document.querySelectorAll('a[href]').length`);\nif (n === 0) console.warn('citylist empty — pass pinyin slug or cityId instead of Chinese name');","typeGuard":null,"tryCatchPattern":"try { return await searchWithCity(chineseName); }\ncatch (e) { if (/citylist did not render/.test(e.message)) { return searchWithCity(PINYIN_FALLBACK[city] || KNOWN_CITY_ID); } throw e; }","preventionTips":["Avoid Chinese city names; use pinyin slugs or numeric cityIds so the citylist lookup is never needed.","Detect and handle Dianping anti-bot walls before scraping citylist.","Add waits for anchors before page.evaluate on citylist.","Maintain your own Chinese-name → pinyin map for your use cases."],"tags":["scraping","dianping","citylist","empty-result"],"backgroundTag":"selector-not-found-scraping","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}