使用BeautifulSoup爬取Oddsportal时的缺失值与URL获取错误问题
解决Oddsportal足球爬虫的两个核心问题:日期URL过滤与比分数据抓取
问题1:过滤无关日历URL,获取目标7个日期页面URL
原因
之前的选择器范围太宽泛,抓取了包括月份跳转、年份导航在内的所有日历相关链接,而非仅顶部导航栏的最近7天赛事页面链接。
解决方案
通过精准的CSS选择器限定抓取范围,仅定位顶部日期导航区域内的足球赛事页面链接:
基于BeautifulSoup的实现
from bs4 import BeautifulSoup import requests # 自定义请求头避免被反爬 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" } base_url = "https://www.oddsportal.com/matches/football/" response = requests.get(base_url, headers=headers) soup = BeautifulSoup(response.text, "html.parser") # 定位顶部日历导航中的日期链接:限制父元素为日历日期容器,且链接指向足球赛事页面 target_links = soup.select("div.calendar__days a[href^='/matches/football/']") # 去重并提取前7个目标URL unique_date_urls = list(set([link["href"] for link in target_links]))[:7] # 拼接完整URL full_urls = [f"https://www.oddsportal.com{url}" for url in unique_date_urls] print(f"成功获取{len(full_urls)}个目标日期URL")
基于Selenium的实现
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get("https://www.oddsportal.com/matches/football/") # 等待日期导航加载完成 wait = WebDriverWait(driver, 10) date_elements = wait.until( EC.presence_of_all_elements_located( (By.CSS_SELECTOR, "div.calendar__days a[href^='/matches/football/']") ) ) # 提取URL并去重,取前7个 target_urls = list(set([elem.get_attribute("href") for elem in date_elements]))[:7] print(f"成功获取{len(target_urls)}个目标日期URL") driver.quit()
关键说明
- 用
div.calendar__days限定抓取范围在顶部日期导航区,排除其他无关日历链接 - 用
[href^='/matches/football/']确保链接指向足球赛事页面,而非其他项目或日历跳转页面 - 去重处理避免重复抓取当天赛事的链接(当天链接可能同时出现在导航和当前页)
问题2:正确抓取赛事比分数据,填充score列
原因
- 比分数据是动态渲染的,静态请求(如requests)无法获取到已加载的内容
- 元素选择器错误,未定位到正确的比分容器
- 未处理未开赛赛事的空比分情况,导致DataFrame生成nan值
解决方案
使用Selenium等待元素加载完成,精准定位比分容器,并针对未开赛赛事做特殊处理:
import pandas as pd from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get("https://www.oddsportal.com/matches/football/") # 等待赛事列表完全加载 wait = WebDriverWait(driver, 15) matches = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.match"))) match_data = [] for match in matches: item = {} # 获取对阵双方 item["teams"] = match.find_element(By.CSS_SELECTOR, "div.match__teams").text.strip() # 获取比分:处理已开赛和未开赛两种情况 try: score_elem = match.find_element(By.CSS_SELECTOR, "div.match__score") score_text = score_elem.text.strip() # 未开赛赛事比分为空,标记为"未开赛" item["score"] = score_text if score_text else "未开赛" except: item["score"] = "未开赛" match_data.append(item) # 生成DataFrame并检查空值 df = pd.DataFrame(match_data) print(f"score列空值数量:{df['score'].isnull().sum()}") driver.quit()
关键说明
- 用
WebDriverWait等待赛事列表加载完成,避免因元素未渲染导致抓取失败 - 通过
div.match__score定位比分容器(可通过F12检查页面元素确认选择器是否准确) - 异常捕获和空值判断处理未开赛赛事,避免生成nan值
- 若需用BeautifulSoup处理,需先通过Selenium获取渲染后的页面源码,再交给BeautifulSoup解析
内容的提问来源于stack exchange,提问作者PyNoob
相关产品推荐
相关产品推荐

