Puppeteer循环点击提取数据异常:仅点首个按钮且报节点脱离错误
Puppeteer循环点击按钮报错「Node is detached from document」的解决办法
问题根源
你预先获取的viewDetails_btns是初始DOM的元素集合,当点击按钮触发页面跳转或DOM重渲染后,原来的元素节点会脱离当前文档树,第二次循环访问viewDetails_btns[i]时就会抛出「Node is detached from document」错误。另外,循环内重复调用waitForSelector(".docBox span.redColorLink")属于无效操作,还可能干扰元素定位。
解决方案
- 不要提前缓存按钮列表,每次循环前重新获取最新的按钮元素,确保节点处于当前文档树中
- 替换固定时长的
waitForTimeout为等待特定DOM状态,提升脚本稳定性 - 返回列表页后,等待页面重新渲染完成再进入下一次循环
修改后的代码
const btnSelector = ".docBox span.redColorLink"; // 先获取总按钮数量,避免循环内重复计算 const totalBtns = await page.$$eval(btnSelector, btns => btns.length); for (let i = 0; i < totalBtns; i++) { console.log("总医生数: ", totalBtns); console.log("当前索引: ", i); // 每次循环重新获取按钮列表,保证元素是当前DOM的有效节点 const viewDetailsBtns = await page.$$(btnSelector); await viewDetailsBtns[i].click(); // 等待详情页目标元素加载完成 await page.waitForSelector("b.ng-tns-c12-0"); // 直接用$eval提取文本,简化代码逻辑 const detailText = await page.$eval("b.ng-tns-c12-0", el => el.innerText); console.log(detailText); // 点击返回按钮回到列表页 await page.waitForSelector("button.btn"); await page.click("button.btn"); // 等待列表页重新渲染完成,确保下一次循环能正确获取按钮 await page.waitForSelector(btnSelector); }
关键改动说明
- 用
$$eval一次性获取总按钮数,避免循环内重复查询DOM - 每次循环重新调用
page.$$(btnSelector)获取按钮,彻底解决节点脱离问题 - 用
$eval合并元素获取与文本提取的逻辑,减少冗余代码 - 去掉固定3秒等待,改用等待列表页按钮重新出现,让脚本适配不同加载速度的页面
内容的提问来源于stack exchange,提问作者Basseloob
相关产品推荐
相关产品推荐

