Selenium爬取英超黄牌统计数据时获取值与HTML实际值不符
问题根因
- 页面异步渲染未完成就执行抓取:你访问的统计页是纯前端动态渲染的,
driver.get()触发跳转后,页面会先加载全历史赛季的俱乐部累计黄牌默认数据,再通过异步接口拉取se=20参数对应赛季的真实数据替换表格内容。你没有等待数据替换完成就直接读取DOM文本,拿到的是默认的历史累计值,和目标赛季的数值自然差异极大。 - 绝对Xpath容错性为0:你使用的从根节点开始逐层索引的绝对Xpath,只要页面插入运营广告、调整DOM层级、新增功能模块,就会出现定位偏移,很容易抓错列的内容。
- 未处理页面前置弹窗:首次访问英超官网会弹出cookie授权弹窗,会阻塞页面JS执行、遮挡内容,进一步导致数据加载异常。
修复代码
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 selenium.webdriver.chrome.service import Service import time chrome_driver_path = "你的chromedriver本地路径" driver = webdriver.Chrome(service=Service(chrome_driver_path)) wait = WebDriverWait(driver, 15) driver.get("https://www.premierleague.com/stats/top/clubs/total_yel_card?se=20") # 处理cookie授权弹窗 try: accept_cookie_btn = wait.until(EC.element_to_be_clickable( (By.XPATH, '//button[@id="onetrust-accept-btn-handler"]') )) accept_cookie_btn.click() except: pass # 等待目标赛季数据加载完成:单赛季俱乐部黄牌数不可能超过200,抓到小于200的数值说明默认历史数据已被替换 wait.until(EC.presence_of_element_located( (By.CSS_SELECTOR, 'tbody tr:first-child td.stats-table__main-stat') )) while True: first_card_val = driver.find_element(By.CSS_SELECTOR, 'tbody tr:first-child td.stats-table__main-stat').text processed_val = int(first_card_val.replace(',', '')) if processed_val < 200: break time.sleep(0.5) cards = {} # 用相对定位遍历表格行,避免绝对路径索引失效 rows = driver.find_elements(By.CSS_SELECTOR, 'table.stats-table tbody tr') for row in rows[:20]: club_name = row.find_element(By.CSS_SELECTOR, 'td a.stats-table__playerName').text # 直接定位带统计值专属class的单元格,避免列索引偏移 card_count = row.find_element(By.CSS_SELECTOR, 'td.stats-table__main-stat').text cards[club_name] = card_count print(cards) driver.quit()
注意点
- 不要使用绝对Xpath定位元素,优先使用元素的class、id等稳定属性做相对定位,避免页面结构微调就导致定位失效。
- 爬取动态渲染页面必须加显式等待,不要页面刚跳转就立刻抓取内容,要等目标元素加载到符合预期的状态再读取数据。
- 数值类内容抓取后可以先做合理性校验,比如单赛季俱乐部黄牌数不可能超过200,一旦抓到上千的数值就说明拿到的是错误的默认数据,等待重新加载即可。
内容的提问来源于stack exchange,提问作者Nuri Taş
相关产品推荐
相关产品推荐

