You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

问题原理解释

  1. 异步执行顺序问题:原代码中element.getProperty()是异步操作(返回Promise),forEach循环不会等待异步操作完成就继续执行,所以循环外的console.log(data)会先于异步回调执行,此时data还未被赋值,自然是undefined。
  2. 变量覆盖问题:用var声明的data在循环中会被多次覆盖,即使异步完成后,最终也只会保留最后一次赋值的结果,无法收集所有数据。

关键修复点

  • 用map替代forEach,将每个元素的异步操作转换成Promise数组,再通过Promise.all()等待所有异步操作完成,确保拿到所有数据后再进行后续处理。
  • 添加元素存在性检查,避免空值调用方法导致报错。
  • 根据实际文本格式拆分国家和联赛(如果网站文本格式不同,只需调整split的分隔符或拆分逻辑即可)。

内容的提问来源于stack exchange,提问作者Bruno Araújo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:12:46