Selenium Java如何无需滚动即可获取全部网页元素值
问题原因
你遇到的是前端**虚拟滚动(懒加载列表)**的典型表现:这类列表为了优化大数量级下的渲染性能,只会把可视区域内的行节点挂载到DOM树上,可视范围外的行不会生成对应的DOM元素,因此不触发滚动加载的前提下,常规DOM选择器永远只能拿到已渲染的20个元素。
不存在完全不滚动就拿到全量DOM元素的通用方案,除非你绕过UI层直接读取页面的原始数据源(比如接口返回值、框架挂载的全局数据),这类方案需要针对页面单独适配,通用性差。
你原有实现存在两个明显缺陷:一是使用固定像素值滚动,无法适配后续元素总量增长到100个的场景;二是如果提前缓存了holdingsValue的元素集合,DOM更新后缓存不会自动刷新,很容易出现漏取元素的问题。
效果参考
- 未滚动时仅能识别20个元素:

- 滚动到对应位置后可识别全部22个元素:

通用实现方案(无需预判滚动距离)
不要写死固定滚动像素值,改用「动态滚动+元素数量校验」的逻辑,自动判断是否加载完全部元素,不管后续元素增长到多少个都能适配,核心逻辑如下:
- 循环将表格容器滚动到当前已加载的最后一行位置,触发懒加载
- 每次滚动后等待列表渲染完成,重新统计Holdings列的元素数量
- 连续两次统计的元素数量完全一致时,说明已经加载到列表底部,停止滚动
- 遍历全量已加载的元素计算求和值
优化后的Java+Selenium代码实现:
import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebElement; import java.util.List; public int getSumOfHoldingsValue() { int lastCount = 0; int currentCount = 0; final int MAX_SCROLL_TIMES = 50; // 防止异常场景下死循环,可根据最大元素量级调整 int scrollTimes = 0; final String HOLDINGS_SELECTOR = "替换为你定位Holdings列元素的CSS选择器"; // 动态滚动直到无新元素加载 do { lastCount = currentCount; List<WebElement> currentElements = driver.findElements(By.cssSelector(HOLDINGS_SELECTOR)); currentCount = currentElements.size(); if (currentCount > 0) { // 滚动到当前最后一个元素位置,触发下一批懒加载 JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript("arguments[0].scrollIntoView({block: 'end'});", currentElements.get(currentCount - 1)); } // 等待短时间让新元素完成渲染,可根据页面响应速度调整 try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } scrollTimes++; } while (lastCount != currentCount && scrollTimes < MAX_SCROLL_TIMES); // 全量元素加载完成后遍历求和 List<WebElement> allHoldings = driver.findElements(By.cssSelector(HOLDINGS_SELECTOR)); int sum = 0; for (WebElement item : allHoldings) { sum += Utils.convertStringToInteger(item.getAttribute("innerText")); } return sum; }
可选优化方案(无需滚动,适配成本高)
如果不想执行滚动操作,可以尝试绕过DOM渲染直接拿全量数据,这类方案执行效率更高,但需要针对当前页面单独适配:
- 打开Chrome控制台检查网络请求,找到加载持仓列表的后端接口,直接用Selenium调用该接口获取全量返回数据,不需要等待DOM渲染,稳定性和速度都更优
- 检查表格容器的DOM属性,React/Vue类框架通常会把组件实例、全量数据挂载在DOM节点的内置属性上(比如
__vue__、__reactProps$开头的属性),可以直接通过JS执行脚本读取全量数据,不需要触发滚动
内容的提问来源于stack exchange,提问作者Pratik Pathare
相关产品推荐
相关产品推荐

