{"record":{"id":"4a11c7dfbbc77317","repo":"xpzouying/xiaohongshu-mcp","slug":"error-4a11c7","errorCode":null,"errorMessage":"未找到商品选择框","messagePattern":"未找到商品选择框","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/publish.go","lineNumber":1313,"sourceCode":"\t\t\tbreak\n\t\t}\n\t\ttime.Sleep(100 * time.Millisecond)\n\t}\n\n\t// 等待商品列表渲染完成（使用与工作代码相同的选择器）\n\tfor time.Now().Before(deadline) {\n\t\tproductList, err := modal.Element(\".goods-list-normal .good-card-container\")\n\t\tif err == nil && productList != nil {\n\t\t\tbreak\n\t\t}\n\t\ttime.Sleep(100 * time.Millisecond)\n\t}\n\ttime.Sleep(500 * time.Millisecond) // 额外等待确保渲染完成\n\n\t// 5. 点击第一个商品的 checkbox（使用与工作代码相同的选择器）\n\tcheckbox, err := modal.Element(\".goods-list-normal .good-card-container .d-checkbox\")\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"未找到商品选择框\")\n\t}\n\n\t// 检查是否已经选中\n\tisChecked, err := checkbox.Eval(`(el) => {\n\t\treturn el.querySelector('.d-checkbox-simulator.checked') !== null ||\n\t\t\t   el.querySelector('input[type=\"checkbox\"]:checked') !== null;\n\t}`)\n\tif err == nil && isChecked.Value.Bool() {\n\t\tslog.Info(\"商品已选中，跳过\", \"keyword\", keyword)\n\t\treturn nil\n\t}\n\n\tif err := humanize.Click(checkbox); err != nil {\n\t\treturn errors.Wrap(err, \"点击商品选择框失败\")\n\t}\n\n\trandomDelay := 800 + rand.Intn(700)\n\ttime.Sleep(time.Duration(randomDelay) * time.Millisecond)","sourceCodeStart":1295,"sourceCodeEnd":1331,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/publish.go#L1295-L1331","documentation":"searchAndSelectProduct 在等待搜索结果列表渲染后，用 .goods-list-normal .good-card-container .d-checkbox 定位第一个商品的勾选框失败：无搜索结果或结果列表/勾选框选择器与页面不符。","triggerScenarios":"调用 searchAndSelectProduct 时：关键词搜索无结果/零商品；页面改版导致 .d-checkbox 类名变化；搜索结果仍在 loading（.goods-list-loading 未消失）或列表容器 .goods-list-normal 尚未渲染；弹窗 modal 元素已失效（页面刷新或弹窗被关闭）。","commonSituations":"选品库中没有匹配关键词的商品（拼写错误、类目下无该商品）；小红书前端升级改了 DOM 结构；网络慢导致固定 sleep 后列表仍未加载完；账号无选品/带货权限导致弹窗内容为空。","solutions":["先手动验证关键词在小红书选品弹窗里能搜到商品，换个确定有结果的关键词重试","增加列表渲染等待：用 rod 的 page.Timeout().Element() 或 WaitStable 轮询 `.goods-list-normal .good-card-container`，而不是固定 time.Sleep","打印 modal 的 HTML（modal.MustElement(\"*\").Page() 或 Eval outerHTML）确认实际 DOM 结构，更新选择器","检查登录态和选品权限，重新登录后再跑"],"exampleFix":"// before\ncheckbox, err := modal.Element(\".goods-list-normal .good-card-container .d-checkbox\")\nif err != nil {\n    return errors.Wrap(err, \"未找到商品选择框\")\n}\n// after\nvar checkbox *rod.Element\nerr := rod.Try(func() {\n    checkbox = modal.Timeout(5 * time.Second).Element(\".goods-list-normal .good-card-container .d-checkbox\")\n})\nif err != nil {\n    html, _ := modal.Eval(`(el) => el.innerHTML`)\n    slog.Warn(\"商品选择框未找到\", \"keyword\", keyword, \"modalHTML\", html.Value.String())\n    return errors.Wrap(err, \"未找到商品选择框\")\n}","handlingStrategy":"retry","validationCode":"// 调用前确认页面有选品弹窗且列表已渲染\nvar hasList bool\nfor i := 0; i < 50; i++ {\n    el, err := page.Element(\".goods-list-normal .good-card-container\")\n    if err == nil && el != nil {\n        hasList = true\n        break\n    }\n    time.Sleep(200 * time.Millisecond)\n}\nif !hasList {\n    return errors.New(\"商品列表未渲染，可能无匹配商品\")\n}","typeGuard":"func hasCheckbox(modal *rod.Element) bool {\n    el, err := modal.Element(\".goods-list-normal .good-card-container .d-checkbox\")\n    return err == nil && el != nil\n}","tryCatchPattern":"if err := searchAndSelectProduct(page, keyword); err != nil {\n    var wrapped *errors.wrapError\n    slog.Warn(\"选品失败，跳过该商品\", \"keyword\", keyword, \"err\", err)\n    _ = wrapped\n    // 记录日志后跳过该商品，不中断整个发布流程\n    return nil\n}","preventionTips":["不要依赖固定 sleep，用轮询/WaitStable 等待列表渲染","关键词先在页面上人工验证有搜索结果","前端改版后用截图/HTML dump 及时更新选择器","对非核心步骤（选品）做降级：失败跳过而非中断发布"],"tags":["selector","dom","automation","go-rod"],"backgroundTag":"selector-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"}