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

Pandas DataFrame格式化及按单场赛事而非全局排名问题

体育赛事爬虫数据输出问题解决方案

问题概述

爬虫抓取多场体育赛事数据生成CSV时,存在两个未解决的需求:

  1. 排名计算:需按单场赛事(而非全局)计算Odds Ranking、Official Rating Ranking等字段的排名,当前全局排名不符合预期;
  2. CSV格式优化:每场赛事数据后需添加空行并重复表头,而非仅在文件末尾添加空行。

当前核心代码片段:

for item in course_racecard:

  for link in a_tag:

        race_link = (times.find_previous('a')['href'])
        full_url = urljoin(url, race_link)


      for item in entries:

        for horse_info in item.find_all(class_='horse_extended'):

                li = item.find_all("li")

                trainer = li[0].text.strip()

                jockey = li[1].text.strip()

                data.append({
                    "Date": date,
                    "Course": race_course,
                    "Times": times.text,
                    #"URL": full_url,
                    "Title": race_title_simple,
                    "Distance": distance,
                    "Runners": number_of_runners,
                    "Age Group": age_group,
                    "Class": race_class_simple,
                    "Going": going,
                    "Surface": surface,
                    "Horse": horse_name,
                    "Trainer": trainer,
                    "Jockey": jockey,
                    "Age": age_simple,
                    "Weight": weight,
                    "Official Rating": rating_simple,
                    "Form": simple_horse_form,
                    "Exchange Back Odds": odds_int,
                    "weight in stone": weight_in_stone,
                    "Timeform Favourites": "",
                })

                df = pd.DataFrame(data)

                df['Going'] = df['Going'].str.replace('Going: ', '')

                df['Surface'] = df['Surface'].str.replace('Surface: ', '')

                df['Distance'] = df['Distance'].str.replace('Distance:  ', '')

                df['Age Group'] = df['Age Group'].str.replace('Age:  ', '')

                df['Runners'] = df['Runners'].str.replace('Runners:  ', '')

                df['Odds Ranking'] = df['Exchange Back Odds'].rank(ascending=False)

                df['Official Rating Ranking'] = df['Official Rating'].rank(ascending=True)

                df['Weight Ranking'] = df['weight in stone'].rank(ascending=True)

解决方案

1. 按单场赛事计算排名

当前代码对整个DataFrame做全局排名,需通过赛事唯一标识字段分组实现单场赛事内的排名计算。

优化后代码:

# 收集所有数据到data列表后,一次性生成DataFrame(移到所有循环外,提升效率)
df = pd.DataFrame(data)

# 数据清洗
df['Going'] = df['Going'].str.replace('Going: ', '')
df['Surface'] = df['Surface'].str.replace('Surface: ', '')
df['Distance'] = df['Distance'].str.replace('Distance:  ', '')
df['Age Group'] = df['Age Group'].str.replace('Age:  ', '')
df['Runners'] = df['Runners'].str.replace('Runners:  ', '')

# 定义能唯一区分单场赛事的字段组合(根据实际数据调整)
race_identifier = ['Date', 'Course', 'Times', 'Title']

# 按单场赛事分组计算排名
df['Odds Ranking'] = df.groupby(race_identifier)['Exchange Back Odds'].rank(ascending=False, method='min')
df['Official Rating Ranking'] = df.groupby(race_identifier)['Official Rating'].rank(ascending=True, method='min')
df['Weight Ranking'] = df.groupby(race_identifier)['weight in stone'].rank(ascending=True, method='min')
  • method='min':处理相同数值的排名逻辑,确保相同值获得相同的最高排名,可根据需求替换为'max'(相同值取最低排名)或'first'(按出现顺序排名);
  • 注意:race_identifier的字段组合必须能唯一标识单场赛事,避免不同赛事被错误归为一组。

2. CSV格式优化:每场赛事后加空行和表头

直接使用df.to_csv()无法实现该格式,需逐赛事处理并写入文件,精确控制每行内容。

实现代码:

import csv

output_path = 'race_results.csv'
header = df.columns.tolist()
race_groups = df.groupby(race_identifier)

with open(output_path, 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    first_group = True
    for _, group_df in race_groups:
        if not first_group:
            # 非首个赛事:先写空行,再写表头
            writer.writerow([])
            writer.writerow(header)
        else:
            # 首个赛事:只写一次表头
            writer.writerow(header)
            first_group = False
        # 写入当前赛事的所有数据行
        for _, row in group_df.iterrows():
            writer.writerow(row.tolist())
  • 该方式用csv.writer精确控制输出,自动处理特殊字符(如逗号)的引号包裹,避免CSV格式错误;
  • 代码逻辑自动跳过最后一场赛事后的空行和表头,避免冗余内容。

额外效率优化

当前代码在horse_info循环内反复执行df = pd.DataFrame(data),每次添加一条数据就重新生成DataFrame,效率极低。建议:

  • 保留data.append()收集所有数据;
  • 把df = pd.DataFrame(data)及后续的清洗、排名代码移到所有循环的最外层,仅执行一次。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 17:02:48