You need to enable JavaScript to run this app. 修改Oddsportal足球赛事爬虫适配全局赛事页解决IndexError报错
优惠活动
大模型
产品
解决方案
定价
更多

修改Oddsportal足球赛事爬虫适配全局赛事页解决IndexError报错

报错根因
  • 原始代码适配的是单联赛详情页,这类页面顶部面包屑导航的a标签有至少3个,对应「网站首页 > 足球 > 国家名 > 联赛名」层级,所以取索引1、2的元素能正常拿到国家、联赛值
  • 你替换的足球赛事聚合页面包屑只有2个a标签,对应「网站首页 > 足球 > 今日赛事」层级,count列表长度仅为2,访问索引2的元素自然触发索引越界
  • 更深层的逻辑问题:聚合页包含多个国家、多个联赛的赛事,原始代码全局只取一次国家、联赛的逻辑本身就不匹配聚合页的结构,需要调整取数逻辑
适配修改后的完整代码
import os
import pandas as pd
from selenium import webdriver
from tabulate import tabulate
from datetime import datetime
import time
from bs4 import BeautifulSoup as bs

start = datetime.now()
pd.set_option('display.max_rows', 5000)
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1000)

browser = webdriver.Chrome()
# 可选:如果页面加载慢可以加隐式等待
browser.implicitly_wait(10)

class GameData:
    def __init__(self):
        self.date = []
        self.time = []
        self.game = []
        self.score = []
        self.home_odds = []
        self.draw_odds = []
        self.away_odds = []
        self.country = []
        self.league = []


def parse_data(url):
    browser.get(url)
    # 等待页面加载完成,避免元素未渲染报错
    time.sleep(3)
    df = pd.read_html(browser.page_source, header=0)[0]
    html = browser.page_source
    soup = bs(html, "lxml")
    game_data = GameData()
    game_date = None
    current_country = None
    current_league = None
    
    for row in df.itertuples():
        if not isinstance(row[1], str):
            continue
        # 识别国家联赛分组头:格式为「国家 - 联赛」,无冒号
        elif ':' not in row[1] and ' - ' in row[1]:
            current_country, current_league = row[1].split(' - ', 1)
            continue
        # 识别日期行
        elif ':' not in row[1]:
            game_date = row[1].split('-')[0]
            continue
        # 跳过没有解析到基础信息的行
        if not current_country or not current_league or not game_date:
            continue
        game_data.date.append(game_date)
        game_data.time.append(row[1])
        game_data.game.append(row[2])
        game_data.score.append(row[3])
        game_data.home_odds.append(row[4])
        game_data.draw_odds.append(row[5])
        game_data.away_odds.append(row[6])
        game_data.country.append(current_country)
        game_data.league.append(current_league)
    return game_data


# 聚合页也可以正常抓取,也可以换回原来的单联赛url测试兼容性
urls = {
    "https://www.oddsportal.com/matches/soccer/"
}

if __name__ == '__main__':
    results = None
    for url in urls:
        try:
            game_data = parse_data(url)
            if game_data is None or len(game_data.game) == 0:
                continue
            result = pd.DataFrame(game_data.__dict__)
            if results is None:
                results = result
            else:
                # 替换旧的append方法,适配新pandas版本
                results = pd.concat([results, result], ignore_index=True)
        except (ValueError, AttributeError) as e:
            # 合并异常捕获逻辑,减少冗余代码
            print(f"抓取过程中出现异常:{e},重试一次")
            game_data = parse_data(url)
            if game_data is None or len(game_data.game) == 0:
                continue
            result = pd.DataFrame(game_data.__dict__)
            if results is None:
                results = result
            else:
                results = pd.concat([results, result], ignore_index=True)

    print(tabulate(results, headers='keys', tablefmt="github"))
    end = datetime.now()
    time_taken = end - start
    print('Time taken to complete: ', time_taken)
核心修改说明
  1. 移除了原来全局取面包屑获取国家、联赛的逻辑,改为遍历表格时动态识别国家联赛分组头(聚合页里每个联赛的赛事前都会单独一行显示「国家 - 联赛」的分组信息)
  2. 新增了当前国家、当前联赛的变量,随遍历过程动态更新,确保每个赛事的国家联赛信息准确
  3. 合并了冗余的异常捕获逻辑,同时替换了已经被pandas废弃的append方法为concat,避免版本兼容警告
  4. 增加了隐式等待和强制等待逻辑,避免页面未加载完成导致的元素获取失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 14:24:09