修改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)
核心修改说明
- 移除了原来全局取面包屑获取国家、联赛的逻辑,改为遍历表格时动态识别国家联赛分组头(聚合页里每个联赛的赛事前都会单独一行显示「国家 - 联赛」的分组信息)
- 新增了当前国家、当前联赛的变量,随遍历过程动态更新,确保每个赛事的国家联赛信息准确
- 合并了冗余的异常捕获逻辑,同时替换了已经被pandas废弃的
append方法为concat,避免版本兼容警告 - 增加了隐式等待和强制等待逻辑,避免页面未加载完成导致的元素获取失败
内容的提问来源于stack exchange,提问作者PyNoob
相关产品推荐
相关产品推荐

