如何在chromedp中按登录状态执行不同代码并解决异常
问题原因分析
- 未登录时偶现节点找不到报错:执行登录相关的点击、输入操作前,没有等待对应DOM节点完全渲染,页面还在加载过程中就触发操作就会返回该错误。同时使用的层级过长的选择器稳定性差,页面结构微小变动就会匹配失败。
- 重复打开GitHub标签页:代码逻辑冗余,判断登录状态时已经完成了一次GitHub导航,后续又重复创建上下文、重复触发同地址导航,导致多开了一个标签页。
修改方案
- 直接复用判断登录状态时的上下文,删除冗余的targetID查询、重复上下文创建、重复导航逻辑,解决多开标签的问题。
- 所有DOM操作前新增
WaitVisible逻辑,等待节点加载完成后再执行操作;登录提交后新增登录成功校验,确保状态正确再执行后续操作,解决偶现找不到节点的问题。 - 精简选择器,提升匹配稳定性。
完整修改后代码
package main import ( "context" "log" "time" "github.com/chromedp/cdproto/cdp" "github.com/chromedp/chromedp" "github.com/chromedp/chromedp/kb" ) func main() { options := append(chromedp.DefaultExecAllocatorOptions[:], chromedp.Flag(`headless`, false), chromedp.DisableGPU, chromedp.Flag(`disable-extensions`, false), chromedp.Flag(`enable-automation`, false), chromedp.UserAgent(`Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36`), ) allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...) defer cancel() browserCtx, cancel := chromedp.NewContext(allocCtx) defer cancel() // 原逻辑打开stackoverflow页面,按需保留即可 if err := chromedp.Run(browserCtx, chromedp.Navigate("https://stackoverflow.com/questions/69672682/how-to-run-different-codes-according-to-login-status-in-chromedp"), ); err != nil { log.Printf("navigate stackoverflow.com err : %v\n", err) } // 创建GitHub操作的上下文,全程复用 githubCtx, cancel := chromedp.NewContext(browserCtx) defer cancel() var userHeaderNode []cdp.NodeID // 10秒超时,打开GitHub并判断登录状态 tCtx, cancel := context.WithTimeout(githubCtx, 10*time.Second) defer cancel() if err := chromedp.Run(tCtx, chromedp.Navigate("https://github.com/chromedp/chromedp"), // 等待页面加载完成后再查询登录态节点 chromedp.WaitReady(`body`), chromedp.NodeIDs(`div.Header-item.position-relative.mr-0.d-none.d-md-flex`, &userHeaderNode, chromedp.ByQuery), ); err != nil { log.Printf("check login status err : %v\n", err) } // 未登录则执行登录逻辑 if len(userHeaderNode) == 0 { if err := chromedp.Run(githubCtx, // 等待登录按钮可见再点击 chromedp.WaitVisible(`a[href="/login"]`, chromedp.ByQuery), chromedp.Click(`a[href="/login"]`, chromedp.ByQuery), // 等待账号输入框可见再输入 chromedp.WaitVisible(`#login_field`, chromedp.ByQuery), chromedp.SendKeys(`#login_field`, `XXX`), // 等待密码输入框可见再输入 chromedp.WaitVisible(`#password`, chromedp.ByQuery), chromedp.SendKeys(`#password`, `XXX`+kb.Enter), // 等待登录成功,用户头象节点出现再执行后续操作 chromedp.WaitVisible(`div.Header-item.position-relative.mr-0.d-none.d-md-flex`, chromedp.ByQuery), ); err != nil { log.Printf("login err : %v\n", err) return } } // 执行切换标签版本的逻辑 if err := chromedp.Run(githubCtx, chromedp.WaitVisible(`#branch-select-menu > summary`, chromedp.ByQuery), chromedp.Click(`#branch-select-menu > summary`, chromedp.ByQuery), chromedp.WaitVisible(`button.SelectMenu-tabs:nth-child(2)`, chromedp.ByQuery), chromedp.Click(`button.SelectMenu-tabs:nth-child(2)`, chromedp.ByQuery), chromedp.WaitVisible(`#tags-menu ref-selector`, chromedp.ByQuery), chromedp.Click(`//*[@id="tags-menu"]/ref-selector/div/div/div/a/span[text()="v0.6.6"]`, chromedp.BySearch), chromedp.Sleep(20*time.Second), ); err != nil { log.Printf("switch tag err : %v\n", err) } }
内容的提问来源于stack exchange,提问作者sSWans
相关产品推荐
相关产品推荐

