如何使用Python抓取HTML弹窗表格/图表?——BestFightOdds网站MMA赛事DraftKings开盘赔率抓取需求
解决MMA赔率抓取中动态弹窗内容的问题
问题描述
我在做一个MMA机器学习项目,要从bestfightodds.com网站抓取每位选手的DraftKings开盘赔率。现在能顺利拿到选手姓名,但开盘赔率得点击DraftKings列对应的赔率值,在弹出的表格里才能看到——这个表格的HTML是点击后才动态生成并加载的,直接用requests拉取静态页面的话,根本找不到这部分内容,所以用BeautifulSoup查找时返回None。
我目前写的代码是这样的:
# Importing packages from bs4 import BeautifulSoup import requests # Specifying website URL html_text = requests.get('https://www.bestfightodds.com/events/ufc-273-2411').text soup = BeautifulSoup(html_text, 'lxml') # Finding values fighter_names = soup.find_all('span', class_ = 't-b-fcc') opening_odds = soup.find_all('span, style_ = 'margin-left: 4px; margin-right: 4px;') for fighter_names in soup.find_all('span', class_ = 't-b-fcc'): print (fighter_names.get_text())
(补充:开盘赔率定位说明——蓝色框是触发弹窗的点击区域,红色框是需要抓取的开盘赔率位置)
核心问题分析
静态HTTP请求(比如requests库)只能获取页面初始加载的HTML,而弹窗里的赔率数据是用户点击后,网站通过AJAX请求动态加载的,所以静态请求拿不到这部分内容。要解决这个问题,得用能模拟浏览器交互行为的工具,比如Selenium,它可以帮你模拟点击操作,等待弹窗加载完成后再抓取数据。
具体解决方案
步骤1:准备工具
首先安装Selenium库:
pip install selenium
然后下载对应你浏览器的驱动(比如Chrome的ChromeDriver),确保驱动版本和浏览器版本匹配,把驱动放在系统能找到的路径,或者在代码里指定驱动路径。
步骤2:编写抓取代码
下面是调整后的代码,实现模拟点击、等待弹窗加载、提取开盘赔率的功能:
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 from bs4 import BeautifulSoup import time # 初始化Chrome浏览器驱动(用其他浏览器的话替换为对应驱动,比如Firefox的GeckoDriver) driver = webdriver.Chrome() # 打开目标赛事页面 driver.get('https://www.bestfightodds.com/events/ufc-273-2411') try: # 等待页面加载完成,找到所有DraftKings的赔率点击元素 draftkings_odds_links = WebDriverWait(driver, 10).until( EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'td[data-book="draftkings"] a')) ) # 遍历每个赔率链接,点击后抓取开盘赔率 for idx, link in enumerate(draftkings_odds_links): # 同一组比赛的两位选手,弹窗只需点击一次即可查看两人数据,所以隔一个点击一次 if idx % 2 == 0: link.click() time.sleep(1) # 给弹窗一点加载时间 # 解析当前页面(包含弹窗)的HTML page_soup = BeautifulSoup(driver.page_source, 'lxml') # 定位开盘赔率元素(根据你提供的样式,这里用style属性定位,实际可能需要根据弹窗真实结构调整) opening_odds = page_soup.find('span', style='margin-left: 4px; margin-right: 4px;') # 获取对应选手的姓名 fighter_name = driver.find_elements(By.CSS_SELECTOR, 'span.t-b-fcc')[idx].text if opening_odds: print(f"选手: {fighter_name} | 开盘赔率: {opening_odds.get_text()}") else: print(f"选手: {fighter_name} | 未找到开盘赔率") # 点击页面空白处关闭弹窗 driver.find_element(By.CSS_SELECTOR, 'body').click() time.sleep(0.5) finally: # 完成抓取后关闭浏览器 driver.quit()
关键注意点
- 选择器调整:如果弹窗的实际HTML结构和你描述的有差异,一定要打开浏览器开发者工具,点击弹窗后查看真实的元素属性,替换代码里的CSS选择器,否则可能抓不到数据。
- 反爬应对:网站可能有反爬机制,建议不要太快地连续点击,适当增加
time.sleep()的时长,也可以设置随机等待时间,避免被封禁IP。 - 效率优化:如果要抓取多个赛事页面,可以复用浏览器实例,不用每次都重新打开关闭,提升抓取效率。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

