场景:用 Selenium 渲染页面后,有一个 Div 是通过 Ajax 渲染出来的,然后碰到了这个异常。
StackOverflow 上的答案,看了一部分,基本都是在说如果第一次拿不到,报了这个异常,则在 catch exception 的时候,再执行一次。 这样做大部分情况可能没问题,但是逻辑始终是有问题的。比如说就算执行两次,但是这两次执行的时间很快,而想要获取的元素此时仍然没有渲染出来怎么办?理论上这个概率挺大的。之所以很多人附议这个答案,我理解还是因为对爬虫的结果精度不那么高,所以有时候拿不到数据也是能容忍的。
本次讨论旨在如何解决这个问题上。这个问题的原因,上面已经说了,那做法理论上就是在元素加载完之后,再去执行 find 动作。selenium 有一个类叫 WebDriverWait,它有很多函数可以使用。
初始化
WebDriverWait wait = new WebDriverWait(driver, waitMillions);
第一个参数为当前的 WebDriver 对象,第二个是超时时间。超时时间的意义在于,如果开发者对当前页面的元素定位有误,也不会影响整个流程,只是会阻塞一段时间。
使用
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(css)));
这是根据 css 选择器,选择元素
wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector(css)))
这是根据 css 选择器,选择一批元素
叨一句
比如我们设置超时时间为 20 秒,那么我们在获取一个元素的时候,这个 20 秒是什么概念呢?
我们假设一个元素获取平均需要 1 秒(只是假设)
在获取这个元素之前,需要等待至少 3 秒(也只是假设,比如异步请求数据就是很慢)
那么正常来说,4秒之内元素渲染完毕了,还需不需要等 16 秒呢?不需要!如果4秒后元素渲染完毕,即执行 find,返回元素对象。