Node.js中Puppeteer的Promise在forEach外取值为undefined问题求助
解决Puppeteer异步数据获取与拆分问题
修复后的代码
try { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); await page.goto("http://m.flashscore.com.br"); // 获取包含赛事的元素 const element = await page.$("div.soccer > div#score-data"); if (!element) { console.log("未找到目标元素"); await browser.close(); return; } // 获取所有h4元素 const dataCountryAndLeague = await element.$$("h4"); if (!dataCountryAndLeague.length) { console.log("未找到国家/联赛数据"); await browser.close(); return; } // 批量获取所有文本内容,处理异步操作 const allTexts = await Promise.all( dataCountryAndLeague.map(async (el) => { const textContent = await el.getProperty("textContent"); return textContent.jsonValue() as Promise<string>; }) ); // 拆分国家和联赛数据(根据实际文本格式调整拆分逻辑) const countryLeagueList = allTexts.map(text => { // 假设文本格式是「国家 - 联赛」,例如 "Brasil - Série A" const [country, league] = text.split(" - ").map(item => item.trim()); return { country, league }; }); console.log("拆分后的数据:", countryLeagueList); // 这里可以按需使用countryLeagueList中的数据 await browser.close(); } catch (error) { console.log("访问页面数据时出错:", error); return "访问页面数据时出错:" + error; }
问题原理解释
- 异步执行顺序问题:原代码中
element.getProperty()是异步操作(返回Promise),forEach循环不会等待异步操作完成就继续执行,所以循环外的console.log(data)会先于异步回调执行,此时data还未被赋值,自然是undefined。 - 变量覆盖问题:用
var声明的data在循环中会被多次覆盖,即使异步完成后,最终也只会保留最后一次赋值的结果,无法收集所有数据。
关键修复点
- 用
map替代forEach,将每个元素的异步操作转换成Promise数组,再通过Promise.all()等待所有异步操作完成,确保拿到所有数据后再进行后续处理。 - 添加元素存在性检查,避免空值调用方法导致报错。
- 根据实际文本格式拆分国家和联赛(如果网站文本格式不同,只需调整
split的分隔符或拆分逻辑即可)。
内容的提问来源于stack exchange,提问作者Bruno Araújo
相关产品推荐
相关产品推荐

