Selenium如何获取页面所有元素(含视口外元素)
问题描述
我理解调用selenium.webdriver实例的find_elements方法时,会返回DOM中所有匹配指定定位器的元素引用。但运行以下代码时,仅获取到不到30个元素,而目标页面实际存在更多元素:
from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By import selenium.webdriver.support.expected_conditions as EC DRIVER_PATH = '/chromedriver' driver = webdriver.Chrome(executable_path=DRIVER_PATH) wait = WebDriverWait(driver, 30) URL = 'https://labs.actionnetwork.com/markets' driver.get(URL) PGA_button = wait.until(EC.presence_of_element_located((By.XPATH, ".//button[@class='btn btn-light' and text()='PGA']"))) driver.execute_script("arguments[0].click();", PGA_button) logos = driver.find_elements(By.XPATH, ".//*[@class='odds-logo ml-1']")
目标元素:
调试时滚动页面会得到不同的元素列表,推测这与视口有关。请问如何获取页面上的所有logos元素?是否有办法获取页面上的所有元素(即使它们在视口外)?
问题分析
页面采用了懒加载机制——只有当元素进入浏览器视口范围时,才会被动态渲染到DOM中。直接调用find_elements只能获取当前已经加载到DOM里的元素,也就是视口内(或已滚动过的区域)的元素。
解决方法
要获取所有元素,需要先触发页面滚动,让所有懒加载的元素都完成渲染,再执行元素定位。以下是两种实用方案:
方案1:循环滚动到页面底部(适配无限滚动页面)
通过重复滚动到页面底部,直到页面高度不再变化,确保所有内容都加载完成:
from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By import selenium.webdriver.support.expected_conditions as EC import time DRIVER_PATH = '/chromedriver' driver = webdriver.Chrome(executable_path=DRIVER_PATH) wait = WebDriverWait(driver, 30) URL = 'https://labs.actionnetwork.com/markets' driver.get(URL) PGA_button = wait.until(EC.presence_of_element_located((By.XPATH, ".//button[@class='btn btn-light' and text()='PGA']"))) driver.execute_script("arguments[0].click();", PGA_button) # 等待初始内容加载 time.sleep(2) last_scroll_height = driver.execute_script("return document.body.scrollHeight") while True: # 滚动到当前页面底部 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 等待懒加载内容加载完成(可根据页面速度调整时长) time.sleep(3) # 获取新的页面高度 new_scroll_height = driver.execute_script("return document.body.scrollHeight") # 高度不再变化则停止滚动 if new_scroll_height == last_scroll_height: break last_scroll_height = new_scroll_height # 此时DOM已包含所有元素,执行定位 logos = driver.find_elements(By.XPATH, ".//*[@class='odds-logo ml-1']") print(f"共找到 {len(logos)} 个logo元素")
方案2:滚动到最后一个目标元素(精准触发加载)
通过定位当前已加载的最后一个目标元素,滚动到它的位置,重复直到没有新元素加载:
# 点击PGA按钮后执行以下逻辑 wait.until(EC.presence_of_element_located((By.XPATH, ".//*[@class='odds-logo ml-1']"))) while True: current_logo_count = len(driver.find_elements(By.XPATH, ".//*[@class='odds-logo ml-1']")) # 获取当前最后一个logo元素 last_logo = driver.find_elements(By.XPATH, ".//*[@class='odds-logo ml-1']")[-1] # 滚动到该元素位置,触发后续内容加载 driver.execute_script("arguments[0].scrollIntoView({behavior: 'smooth', block: 'end'});", last_logo) # 等待新元素加载,这里用显式等待替代固定休眠更稳定 try: wait.until(lambda d: len(d.find_elements(By.XPATH, ".//*[@class='odds-logo ml-1']")) > current_logo_count) except: # 没有新元素加载,退出循环 break # 获取所有logo元素 logos = driver.find_elements(By.XPATH, ".//*[@class='odds-logo ml-1']")
补充优化建议
- 避免使用固定的
time.sleep(),改用WebDriverWait等待元素数量变化,能提升代码稳定性,适配不同加载速度的页面; - 部分页面的懒加载触发条件是元素距离视口一定距离,
scrollIntoView()的参数可以调整(比如block: 'center')来提前触发加载。
内容的提问来源于stack exchange,提问作者HJA24
相关产品推荐
相关产品推荐

