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

Puppeteer选择器仅返回单个元素:无法获取全部足球赛事数据求助

Puppeteer爬取Flashscore赛事数据仅返回单场的解决方案

问题背景

使用Puppeteer开发API获取https://www.flashscore.com.br的足球赛事数据,用于移动端应用,但脚本仅返回单场赛事数据,而非所有赛事。

原服务文件代码

import puppeteer from "puppeteer";

class NextGamesService {

    async execute() {

        const browser = await puppeteer.launch({ headless: false });
        const page = await browser.newPage();
        await page.goto('https://www.flashscore.com.br');

        const games = await page.$$('#live-table > section > div > div');

        const game1 = []

        for (const game of games) {


            const time = await page.evaluate((el) => el.querySelector('#g_1_IcYs8jIk > div.event__time')?.textContent, game)

            const home = await page.evaluate((el) => el.querySelector('div.event__participant.event__participant--home')?.textContent, game)

            const away = await page.evaluate((el) => el.querySelector('div.event__participant.event__participant--away')?.textContent, game)

            const league = await page.evaluate((el) => el.querySelector('div.icon--flag.event__title.fl_81 > div > span.event__title--name')?.textContent, game)

            game1.push({ time, home, away, league});
        }

        return ({game1})
    }
}

export { NextGamesService }

原控制器代码

import { NextGamesService } from "./nextGamesService";
import { Request, Response } from "express";

class NextGamesController {

    async handle(req: Request, res: Response) {

        const nextGamesService =new NextGamesService();

        const games = await nextGamesService.execute()

        return res.json(games)
    }
}

export {NextGamesController}

当前错误响应

{
    "game1": [
        {
            "time": "11:30",
            "home": "Dortmund",
            "away": "Augsburg",
            "league": "Bundesliga"
        }
    ]
}

问题原因

  1. 时间选择器用固定ID:#g_1_IcYs8jIk是单场赛事的唯一ID,所有循环迭代都只会获取同一场的时间。
  2. 联赛选择器用固定类:.fl_81是特定联赛的标识类,无法匹配其他联赛的赛事。
  3. 元素定位不准确:原赛事选择器未精准匹配所有赛事元素,且未等待页面动态加载完成。
  4. 多次调用page.evaluate:循环内重复调用该方法,效率低且易出现上下文冲突。

修复后的服务文件代码

import puppeteer from "puppeteer";

class NextGamesService {
    async execute() {
        const browser = await puppeteer.launch({ headless: false });
        const page = await browser.newPage();
        await page.goto('https://www.flashscore.com.br');

        // 等待赛事元素加载完成,处理页面动态渲染
        await page.waitForSelector('#live-table .event__match');

        // 一次性获取所有赛事数据,避免多次evaluate调用
        const gameData = await page.evaluate(() => {
            // 获取所有赛事元素
            const gameElements = Array.from(document.querySelectorAll('#live-table .event__match'));
            
            return gameElements.map(game => {
                // 从当前赛事元素内获取相对数据
                const time = game.querySelector('.event__time')?.textContent?.trim();
                const home = game.querySelector('.event__participant--home')?.textContent?.trim();
                const away = game.querySelector('.event__participant--away')?.textContent?.trim();
                // 从赛事所在的联赛板块获取联赛名称
                const league = game.closest('section')?.querySelector('.event__title--name')?.textContent?.trim();

                return { time, home, away, league };
            }).filter(item => item.time && item.home && item.away); // 过滤无效数据
        });

        await browser.close(); // 关闭浏览器,避免资源泄漏
        return { games: gameData };
    }
}

export { NextGamesService }

关键修改说明

  • 等待动态元素:用page.waitForSelector确保赛事元素渲染完成后再抓取,避免因页面加载慢导致的元素缺失。
  • 相对选择器:所有数据选择器基于当前赛事元素或其父级联赛板块,彻底摆脱固定ID/类的限制。
  • 单次page.evaluate调用:一次性处理所有赛事数据,大幅提升效率并避免上下文问题。
  • 过滤无效数据:移除未完全加载的赛事条目,保证返回数据的有效性。
  • 关闭浏览器:添加browser.close()防止资源长时间占用。

内容的提问来源于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.04 01:05:18