使用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()
关键调整说明
- 实时收集数据:每次滚动后立即抓取当前DOM中的所有行,用集合记录已抓取的player名字,避免重复;
- 终止条件优化:通过比较已抓取数据的数量是否变化,判断是否还有新数据加载;
- 滚动方式调整:使用
scrollIntoView的smooth行为,确保页面有足够时间加载新内容; - 异常处理:跳过加载不完整的行,避免脚本中断。
补充:既然你已经通过
requests直接调用API拿到了全部数据,这种方式比Selenium效率高得多,优先推荐使用API接口爬取。
内容的提问来源于stack exchange,提问作者SMTH
相关产品推荐
相关产品推荐

