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

使用Cheerio JS提取赛事赔率并按场次聚合存储的技术求助

解决Cheerio爬取赛事表格时的同场次赔率聚合问题

我正在用Node.js和Cheerio练习网页爬取,需要从下方的赛事HTML表格中提取每场比赛的主队赔率(Home Odds)和客队赔率(Away Odds),将单个赔率存入对象后,把同一场次的所有赔率对象聚合到对应赛事的odds数组中。目前我的实现代码无法正确完成聚合,请求帮忙修正。

示例HTML表格

<table>
  <thead>
    <tr>
      <th>Match Date</th>
      <th>League</th>
      <th>Win (Home Team)</th>
      <th>Home Odds</th>
      <th>Radish (Standard)</th>
      <th>Away Odds</th>
      <th>Lose (Away Team)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>04-24 19:00</td>
      <td>Ukraine D1</td>
      <td>Dnipro-1</td>
      <td>1.26</td>
      <td>5.11</td>
      <td>9.67</td>
      <td>Rukh Lviv</td>
    </tr>
    <tr>
      <td>04-24 19:00</td>
      <td>Ukraine D1</td>
      <td>Dnipro-1</td>
      <td>1.87</td>
      <td>2.75</td>
      <td>1.87</td>
      <td>Rukh Lviv</td>
    </tr>
    <tr>
      <td>04-24 20:00</td>
      <td>Ukraine D1</td>
      <td>FC Oleksandriya</td>
      <td>1.58</td>
      <td>3.59</td>
      <td>5.51</td>
      <td>FC Inhulets Petrove</td>
    </tr>
    <tr>
      <td>04-24 20:00</td>
      <td>Ukraine D1</td>
      <td>FC Oleksandriya</td>
      <td>1.82</td>
      <td>2.25</td>
      <td>1.92</td>
      <td>FC Inhulets Petrove</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td>04-24 21:00</td>
      <td>PBA</td>
      <td>Meralco Bolts</td>
      <td>1.26</td>
      <td>5.11</td>
      <td>9.67</td>
      <td>Barangay Ginebra</td>
    </tr>
    <tr>
      <td>04-24 21:00</td>
      <td>PBA</td>
      <td>Meralco Bolts</td>
      <td>1.87</td>
      <td>2.75</td>
      <td>1.87</td>
      <td>Barangay Ginebra</td>
    </tr>
    <tr>
      <td>04-24 22:00</td>
      <td>PBA</td>
      <td>San Miguel Beermen</td>
      <td>1.58</td>
      <td>3.59</td>
      <td>5.51</td>
      <td>Blackwater</td>
    </tr>
    <tr>
      <td>04-24 22:00</td>
      <td>PBA</td>
      <td>San Miguel Beermen</td>
      <td>1.82</td>
      <td>2.25</td>
      <td>1.92</td>
      <td>Blackwater</td>
    </tr>
  </tbody>
</table>

当前实现代码

初始爬取代码

const data = [];
const $table = $("table > tbody");
let odds = [];

$table.find("tr").each((i, row) => {
  const $trs = $(row);

  const $date = $trs.find("td:first").text().trim();
  const $league_name = $trs.find("td:nth-child(2)").text().trim();
  const $home_team = $trs.find("td:nth-child(3)").text().trim();
  const $away_team = $trs.find("td:last").text().trim();

  // Odds
  const $home_odds = $trs.find("td:nth-child(4)").text().trim();
  const $away_odds = $trs.find("td:nth-child(6)").text().trim();

  let game_odds = {};

  game_odds = {
    home: $home_odds,
    away: $away_odds,
  };

  odds.push(game_odds);

  data.push({
    date: $date,
    league_name: $league_name,
    home_team: $home_team,
    away_team: $away_team,
    odds,
  });
});

去重处理代码

let finalData = [];
let previousLeague = null;
let previousHomeTeam = null;
let previousAwayTeam = null;

for (let i = 0; i < data.length; i++) {
  if (data[i].league_name === previousLeague) {
    if (
      data[i].home_team === previousHomeTeam &&
      data[i].away_team === previousAwayTeam
    ) {
      // The odds of that match is pushed to the finalData array
    } else {
      previousHomeTeam = data[i].home_team;
      previousAwayTeam = data[i].away_team;

      finalData.push({
        date: data[i].date,
        league_name: data[i].league_name,
        home_team: data[i].home_team,
        away_team: data[i].away_team,
      });
    }
  } else {
    previousLeague = data[i].league_name;
  }
}

预期输出

[
  {
    date: '04-24 19:00',
    league_name: 'Ukraine D1',
    home_team: 'Dnipro-1',
    away_team: 'Rukh Lviv',
    odds: [
        {
            home: 1.26,
            away: 9.67,
        },
        {
            home: 1.87,
            away: 1.87,
        },
    ]
  },
  {
    date: '04-24 20:00',
    league_name: 'Ukraine D1',
    home_team: 'FC Oleksandriya',
    away_team: 'FC Inhulets Petrove',
    odds: [
        {
            home: 1.58,
            away: 5.51,
        },
        {
            home: 1.82,
            away: 1.92,
        },
    ]
  },
  {
    date: '04-24 21:00',
    league_name: 'PBA',
    home_team: 'Meralco Bolts',
    away_team: 'Barangay Ginebra',
    odds: [
        {
            home: 1.26,
            away: 9.67,
        },
        {
            home: 1.87,
            away: 1.87,
        },
    ]
  },
  {
    date: '04-24 22:00',
    league_name: 'PBA',
    home_team: 'San Miguel Beermen',
    away_team: 'Blackwater',
    odds: [
        {
            home: 1.58,
            away: 5.51,
        },
        {
            home: 1.82,
            away: 1.92,
        },
    ]
  }
]

问题分析

你的代码存在两个核心问题:

  1. 初始爬取时使用全局odds数组,每遍历一行就追加当前赔率,导致每个赛事对象的odds都包含所有历史赔率,而非仅当前赛事的。
  2. 去重逻辑仅处理了赛事条目去重,但未实现将对应赔率聚合到已有赛事对象的逻辑。

修正后的代码

我们可以通过唯一标识分组的方式,在遍历过程中直接完成赛事和赔率的聚合,无需后续去重:

const finalData = [];
// 用对象存储已存在的赛事,键为唯一标识
const matchMap = {};

$("table > tbody tr").each((i, row) => {
  const $tr = $(row);
  
  // 提取赛事基础信息
  const date = $tr.find("td:first").text().trim();
  const league_name = $tr.find("td:nth-child(2)").text().trim();
  const home_team = $tr.find("td:nth-child(3)").text().trim();
  const away_team = $tr.find("td:last").text().trim();
  
  // 提取当前赔率并转为数值类型
  const home_odds = parseFloat($tr.find("td:nth-child(4)").text().trim());
  const away_odds = parseFloat($tr.find("td:nth-child(6)").text().trim());
  const currentOdds = { home: home_odds, away: away_odds };
  
  // 生成唯一标识,确保同场次赛事被正确分组
  const matchKey = `${date}-${league_name}-${home_team}-${away_team}`;
  
  if (matchMap[matchKey]) {
    // 赛事已存在,追加当前赔率到odds数组
    matchMap[matchKey].odds.push(currentOdds);
  } else {
    // 赛事不存在,创建新对象并加入结果集合
    const newMatch = {
      date,
      league_name,
      home_team,
      away_team,
      odds: [currentOdds]
    };
    matchMap[matchKey] = newMatch;
    finalData.push(newMatch);
  }
});

console.log(finalData);

代码说明

  1. 唯一标识分组:用日期-联赛-主队-客队作为唯一键,确保同一场次的赛事被归为一组。
  2. 实时聚合:遍历每一行时直接判断赛事是否存在,存在则追加赔率,不存在则新建赛事对象,一次遍历完成所有逻辑。
  3. 数据类型转换:将赔率字符串转为数值类型,符合预期输出的格式要求。
  4. 简化流程:避免了先收集重复数据再去重的冗余操作,提升了代码效率。

内容的提问来源于stack exchange,提问作者HilthPH

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 20:24:56