Puppeteer中XPath遍历子节点时textContent批量输出的解决方法
解决Puppeteer中XPath节点数组forEach异步遍历一次性输出的问题
这是因为forEach并不会等待异步回调函数完成——你在forEach里写的async回调,forEach本身根本不会去处理它返回的Promise。所以所有的getProperty和jsonValue操作会几乎同时被启动,等它们各自异步完成后,结果就会批量打印出来,看起来像是一次性输出。
咱们可以用**for...of循环**来替代forEach,它能完美处理异步迭代,确保每个异步操作完成后再进行下一次循环,这样就能实现逐个输出的效果:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false, }); const page = await browser.newPage(); await page.goto('http://127.0.0.1:5500/index.html'); await page.waitForXPath('/html/body/div/div[2]') const [liveDiv] = await page.$x('/html/body/div/div[2]'); const [liveDivParent] = await liveDiv.$x('..'); const childArr = await liveDivParent.$x('/*') // 用for...of替代forEach,串行处理每个异步操作 for (const el of childArr) { const textC = await el.getProperty('textContent'); const textJ = await textC.jsonValue(); console.log(textJ); } await browser.close(); })();
为什么这个方法有效?
for...of会尊重循环体内的await关键字:每次迭代时,它会等待当前的getProperty和jsonValue异步操作全部完成,才会进入下一次循环去处理下一个节点。这样每个子节点的文本内容就会被依次获取并打印,完全符合你想要的逐个输出的需求。
如果你的场景允许并行处理所有节点(但还是希望结果按顺序输出),也可以用Promise.all,不过这种方式最终还是会一次性打印所有结果,所以如果要逐个输出,for...of是最优选择:
// 并行处理示例(结果会一次性输出) await Promise.all(childArr.map(async (el) => { const textC = await el.getProperty('textContent'); const textJ = await textC.jsonValue(); console.log(textJ); }));
内容的提问来源于stack exchange,提问作者RogerKint
相关产品推荐
相关产品推荐

