{"record":{"id":"5330da01279f1cf2","repo":"xpzouying/xiaohongshu-mcp","slug":"get-qrcode-src-failed","errorCode":null,"errorMessage":"get qrcode src failed","messagePattern":"get qrcode src failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/login.go","lineNumber":104,"sourceCode":"\n\treturn nil\n}\n\nfunc (a *LoginAction) FetchQrcodeImage(ctx context.Context) (string, bool, error) {\n\tpp := a.page.Context(ctx)\n\n\t// 导航到小红书首页，这会触发二维码弹窗\n\tpp.MustNavigate(\"https://www.xiaohongshu.com/explore\").MustWaitLoad()\n\n\ttime.Sleep(2 * time.Second)\n\n\tif exists, _, _ := pp.Has(\".main-container .user .link-wrapper .channel\"); exists {\n\t\treturn \"\", true, nil\n\t}\n\n\tsrc, err := pp.MustElement(\".login-container .qrcode-img\").Attribute(\"src\")\n\tif err != nil {\n\t\treturn \"\", false, errors.Wrap(err, \"get qrcode src failed\")\n\t}\n\tif src == nil || len(*src) == 0 {\n\t\treturn \"\", false, errors.New(\"qrcode src is empty\")\n\t}\n\n\treturn *src, false, nil\n}\n\nfunc (a *LoginAction) WaitForLogin(ctx context.Context) bool {\n\tpp := a.page.Context(ctx)\n\tticker := time.NewTicker(500 * time.Millisecond)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn false\n\t\tcase <-ticker.C:","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/login.go#L86-L122","documentation":"FetchQrcodeImage navigates to the xiaohongshu explore page, checks whether the user is already logged in, and otherwise locates the login QR-code image (.login-container .qrcode-img) and reads its src attribute. 'get qrcode src failed' wraps the rod error from MustElement/Attribute — normally that the QR-code element was not found within rod's default element-wait timeout, so no login dialog was rendered.","triggerScenarios":"Calling FetchQrcodeImage while already logged in but the .channel presence check (Has) misses due to selector drift, so the code proceeds to look for a QR dialog that never appears; the login dialog renders slowly or under a different class name after a site update; anti-bot measures show a slider/captcha instead of the QR code; the page failed to fully load in the 2s fixed sleep window.","commonSituations":"Reusing a session cookie so no QR appears but the login-status selector changed; running headless and getting a risk-control page instead of the normal login modal; xiaohongshu renaming .login-container/.qrcode-img in a front-end release; slow network making 2 seconds insufficient for the modal.","solutions":["First confirm login state independently: if already logged in, don't call FetchQrcodeImage — check the returned second bool or verify the .channel element yourself","Replace the fixed time.Sleep(2s) with an explicit wait for the .login-container .qrcode-img selector (rod's Element already polls; extend the page timeout)","Dump the page HTML (page.MustElement(\"body\").MustHTML()) when this fires to see whether a captcha/slider or a redesigned login modal replaced the QR dialog","Update the CSS selectors to match the current xiaohongshu login DOM after inspecting the live page","Check for risk-control/anti-bot interstitials; consider a real browser profile (user data dir) instead of a clean headless one"],"exampleFix":"// before\npp.MustNavigate(\"https://www.xiaohongshu.com/explore\").MustWaitLoad()\ntime.Sleep(2 * time.Second)\n// after\npp.MustNavigate(\"https://www.xiaohongshu.com/explore\").MustWaitLoad()\npp.Timeout(30 * time.Second).MustElement(\".login-container .qrcode-img\") // explicit wait instead of fixed sleep\nsrc, err := pp.Timeout(10*time.Second).Element(\".login-container .qrcode-img\")","handlingStrategy":"validation","validationCode":"// check login state before requesting a QR code\nexists, q, err := page.Has(\".main-container .user .link-wrapper .channel\")\nif err == nil && exists { return \"\", true, nil } // already logged in","typeGuard":"func qrDialogVisible(p *rod.Page) bool {\n    el, err := p.Timeout(2*time.Second).Element(\".login-container .qrcode-img\")\n    return err == nil && el != nil\n}","tryCatchPattern":"src, loggedIn, err := login.FetchQrcodeImage(ctx)\nif err != nil {\n    if strings.Contains(err.Error(), \"get qrcode src failed\") {\n        // dialog absent: maybe already logged in or a captcha page; inspect page HTML\n        html, _ := page.Element(\"body\")\n        log.Printf(\"login page state: %v\", html)\n    }\n    return err\n}","preventionTips":["Short-circuit on logged-in state before calling FetchQrcodeImage","Expect selector drift: xiaohongshu's login modal DOM can change without notice","On headless runs, watch for risk-control slider pages replacing the QR dialog","Use a persistent browser profile so repeat runs are often already logged in"],"tags":["rod","selector","scraping","login","qrcode"],"backgroundTag":"element-not-found","analyzedSha":"332d196854a9eac0d2b8c2c0e3d0cc43139d724c","analyzedAt":"2026-09-05T22:22:55.988Z","contentChangedAt":"2026-09-05T22:22:55.988Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}