{"record":{"id":"44eb08d79f8209f1","repo":"jackwener/OpenCLI","slug":"dianping-member-page-rendered-but-no-user-id-link","errorCode":null,"errorMessage":"Dianping member page rendered but no user_id link found — stale dper or layout drift","messagePattern":"Dianping member page rendered but no user_id link found — stale dper or layout drift","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/dianping/auth.js","lineNumber":31,"sourceCode":"  await page.goto('https://www.dianping.com/member/myinformation');\n  await page.wait(2);\n  const finalUrl = await page.evaluate(`location.href`);\n  if (/account\\.dianping\\.com\\/(pc)?login/.test(String(finalUrl || ''))) {\n    throw new AuthRequiredError('dianping.com', `Dianping member page redirected to login: ${finalUrl}`);\n  }\n  const info = await page.evaluate(`\n    (() => {\n      const nicknameEl = document.querySelector('.user-name, .username, .nickname, .user-info .name');\n      const nickname = (nicknameEl?.textContent || '').trim();\n      const profileLink = Array.from(document.querySelectorAll('a[href*=\"/member/\"]'))\n        .map(a => a.getAttribute('href') || '')\n        .find(h => /\\\\/member\\\\/\\\\d+/.test(h));\n      const uidMatch = String(profileLink || '').match(/\\\\/member\\\\/(\\\\d+)/);\n      return { user_id: uidMatch?.[1] || '', nickname };\n    })()\n  `);\n  if (!info?.user_id) {\n    throw new CommandExecutionError('Dianping member page rendered but no user_id link found — stale dper or layout drift');\n  }\n  return { user_id: String(info.user_id), nickname: String(info.nickname || '') };\n}\n\nregisterSiteAuthCommands({\n  site: 'dianping',\n  domain: 'dianping.com',\n  loginUrl: 'https://account.dianping.com/pclogin',\n  columns: ['user_id', 'nickname'],\n  quickCheck: hasDianpingSessionCookie,\n  verify: verifyDianpingIdentity,\n  poll: async (page) => {\n    if (!await hasDianpingSessionCookie(page)) {\n      throw new AuthRequiredError('dianping.com', 'Waiting for Dianping dper cookie');\n    }\n    return verifyDianpingIdentity(page);\n  },\n});","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/dianping/auth.js#L13-L49","documentation":"CommandExecutionError raised when the Dianping member page renders but the DOM scrape finds no /member/<digits> profile link, so no user_id can be extracted. The library assumes either the dper session is stale (page rendered a logged-out shell) or Dianping's page layout changed. It is a scraping-contract failure, not an auth error per se.","triggerScenarios":"verifyDianpingIdentity loads /member/myinformation, passes the login-redirect check, but page.evaluate returns {user_id: ''} because no anchor matching a[href*='/member/'] with /member/\\d+ exists in the DOM.","commonSituations":"Dianping redesigned the member page selectors; page still loading when evaluate runs (fixed 2s wait too short); logged-out or bot-challenge variant of the page rendered; regional/AB-tested layout without the profile link.","solutions":["Re-login to refresh the dper session, then retry — a stale session often renders a logged-out page without the profile link.","Increase the wait before evaluate (wait for the .user-name/.member link selector instead of a fixed 2s) and retry.","Inspect the live page HTML and update the selectors in auth.js (nickname/user_id extraction) if Dianping changed its layout.","Save the page HTML/screenshot on failure to distinguish layout drift from a bot/verification page."],"exampleFix":"// before\nawait page.wait(2);\nconst info = await page.evaluate(...);\n// after\nawait page.waitForSelector('a[href*=\"/member/\"]', { timeout: 10000 }).catch(() => null);\nconst info = await page.evaluate(...);","handlingStrategy":"retry","validationCode":"await page.waitForSelector('a[href*=\"/member/\"]', { timeout: 10000 }).catch(() => null);\n// only then call verify","typeGuard":"function extractUserId(html) { const m = String(html||'').match(/\\/member\\/(\\d+)/); return m ? m[1] : null; }","tryCatchPattern":"try { identity = await cli.dianping.verify(); }\ncatch (e) { if (e.name === 'CommandExecutionError' && /user_id link found/.test(e.message)) { await page.reload({ waitUntil: 'networkidle' }); identity = await cli.dianping.verify(); } else throw e; }","preventionTips":["Wait for the profile anchor selector instead of a fixed sleep before scraping.","Screenshot/save HTML on failure to distinguish layout drift from bot walls.","Keep the scraping selectors in auth.js updated when Dianping redesigns.","Retry once after a fresh navigation before giving up."],"tags":["scraping","dom-selector","dianping","layout-change"],"backgroundTag":"selector-not-found-scraping","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}