You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Selenium爬取懒加载MLB表格数据不全问题求助

懒加载表格Selenium爬取问题分析与解决

问题原因

你的Selenium脚本只能拿到最后16条数据,核心原因是该网站采用了**虚拟滚动(Virtual Scrolling)**机制:

  • 表格不会一次性渲染所有240条数据,仅在视口中显示当前可见的行;
  • 向下滚动时,页面会移除已离开视口的旧行DOM元素,仅保留当前视口附近的行;
  • 原脚本等滚动完成后再一次性抓取所有行,此时DOM中只剩最后加载的16条,自然只能爬取到这些。

另外原滚动逻辑存在漏洞:通过元素对象是否相等判断滚动终点,但虚拟滚动下旧元素被移除后,新的最后一个元素对象每次都会变化,可能导致循环提前终止或无法真正滚到底部。

修复后的Selenium脚本

要解决这个问题,需要在滚动过程中实时收集已加载的元素,同时避免重复抓取。以下是调整后的代码:

import time
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
from webdriver_manager.chrome import ChromeDriverManager

link = 'https://fantasyteamadvice.com/dfs/mlb/ownership'

def get_content(driver, link):
    driver.get(link)
    # 存储已抓取的player名字,避免重复
    collected_players = set()
    last_count = 0
    
    while True:
        # 等待当前所有行加载完成
        rows = WebDriverWait(driver, 20).until(
            EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".ownership-table-container [class$='player-row']"))
        )
        # 遍历当前行,收集未抓取过的数据
        for elem in rows:
            try:
                player = elem.find_element(By.CSS_SELECTOR, "[data-testid='ownershipPlayer']").text
                if player not in collected_players:
                    logo = elem.find_element(By.CSS_SELECTOR, "[data-testid='ownershipPlayerTeam'] > img").get_attribute("alt")
                    dkprice = elem.find_element(By.CSS_SELECTOR, "[data-testid='ownershipPlayerDkPrice']").text
                    collected_players.add(player)
                    yield player, logo, dkprice
            except Exception as e:
                # 跳过加载不完整的行
                continue
        
        # 判断是否还有新数据加载
        if len(collected_players) == last_count:
            break
        last_count = len(collected_players)
        
        # 滚动到最后一行,触发新数据加载
        last_row = driver.find_element(By.CSS_SELECTOR, ".ownership-table-container [class$='player-row']:last-child")
        driver.execute_script("arguments[0].scrollIntoView({behavior: 'smooth', block: 'end'});", last_row)
        time.sleep(2)  # 根据页面加载速度调整等待时间

if __name__ == '__main__':
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
    try:
        count = 0
        for item in get_content(driver, link):
            print(item)
            count +=1
        print(f"总共抓取到{count}条数据")
    finally:
        driver.quit()

关键调整说明

  1. 实时收集数据:每次滚动后立即抓取当前DOM中的所有行,用集合记录已抓取的player名字,避免重复;
  2. 终止条件优化:通过比较已抓取数据的数量是否变化,判断是否还有新数据加载;
  3. 滚动方式调整:使用scrollIntoView的smooth行为,确保页面有足够时间加载新内容;
  4. 异常处理:跳过加载不完整的行,避免脚本中断。

补充:既然你已经通过requests直接调用API拿到了全部数据,这种方式比Selenium效率高得多,优先推荐使用API接口爬取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 12:23:21