Python中的Java FluentWait

14 投票
4 回答
11524 浏览
提问于 2025-04-20 11:51

在Java的selenium-webdriver包里,有一个叫做FluentWait的类:

每个FluentWait实例都定义了等待某个条件的最长时间,以及检查这个条件的频率。此外,用户还可以设置在等待时忽略特定类型的异常,比如在页面上查找元素时遇到的NoSuchElementExceptions。

换句话说,FluentWait比隐式等待和显式等待更高级,它让你对等待元素的过程有更多的控制。这在很多情况下都非常有用。

Python的selenium包中,有类似的功能吗?还是说我需要自己实现一个?

(我查过等待的文档 - 里面没有相关内容。)

4 个回答

1

根据上面的某个回答,WebDriverWait类有一些可选的参数,比如超时时间、轮询频率和忽略的异常。此外,如果现有的预期条件不符合你的需求,你可以按照这里的文档创建自定义的等待条件,链接在这里 https://selenium-python.readthedocs.io/waits.html。下面是一个代码示例,它会不断检查,直到元素有了预期的文本。

wait=WebDriverWait(driver,timeout=10,poll_frequency=1)
element=wait.until(element_has_text((By.CSS_SELECTOR,"div#finish>h4"),"Hello World!"))

class element_has_text(object):
"""An expectation for checking that an element has a particular text.

locator - used to find the element
returns the WebElement once it has the particular text
"""
def __init__(self,locator,expected_text):
    self.locator=locator
    self.expected_text=expected_text

def __call__(self,driver):
    element = driver.find_element(*self.locator)
    if (element.text==self.expected_text):
        return element
    else:
        return False
1

上面的实现方法在我的使用场景中效果不好,所以我也想分享一下我的实现方式。对于流畅等待(fluent wait),在轮询时检查其他条件也是很有用的,比如我们可以检查某个元素的属性是否发生了变化。因此,在我的情况下,页面应该被刷新。下面是代码(这个代码调整为30秒,也就是循环6次,每秒检查5次):

element = None
i = 6
while element is None:
    try:
        wait = WebDriverWait(driver, 5, poll_frequency=1)
        element = wait.until(expected_conditions.visibility_of_element_located(el))
    except:
        driver.refresh()
        i = i - 1
        print(i)
        if i < 0:
            raise Exception('Element not found')
8

iChar的回答讲了如何在Python中使用WebDriverWait来实现Java中的FluentWait的功能。不过,有些问题没有被提到:

换句话说,FluentWait比隐式等待和显式等待要更复杂一些。

其实不是的。根据Selenium 2.42.x版本的说明,Selenium只实现了两种等待方式:隐式等待和显式等待。FluentWait并不是这两种等待之外的东西,它其实就是一种显式等待。

在Python的Selenium包中,有没有类似的东西,还是我自己实现一个?

我能想到的Python的WebDriverWait实现中缺少的,正是FluentWait(以及它的扩展WebDriverWait)所具备的一个特点:

FluentWait(以及扩展的WebDriverWait可以在运行时动态调整超时时间和轮询间隔。

[引用自这个链接]

Python中的WebDriverWait类设计得是,一旦创建就固定了配置值,不能再更改。而FluentWait则允许在创建后修改配置。所以,一个单一的 FluentWait对象(或者Java中的任何WebDriverWait)可以被重复使用,以不同的轮询频率等待不同的条件。在Python中,如果你想用不同的轮询频率,就必须创建一个新的WebDriverWait对象。

所以,Python的实现确实缺少了某些功能,但我认为这并不足以让人觉得需要去实现一个新的功能。

25

我觉得你可以用Python来做到这一点,不过它的实现没有FluentWait类那么简单。你提供的文档里有提到一些内容,但没有详细讲解。

WebDriverWait类有一些可选的参数,比如超时时间、轮询频率和忽略的异常。所以你可以在这里设置这些参数。然后再结合一个期望条件,来等待元素出现、可点击等等……下面是一个例子:

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.common.exceptions import *

driver = webdriver.Firefox()
# Load some webpage
wait = WebDriverWait(driver, 10, poll_frequency=1, ignored_exceptions=[ElementNotVisibleException, ElementNotSelectableException])
element = wait.until(EC.element_to_be_clickable((By.XPATH, "//div")))

显然,你可以把等待和元素操作合并成一个语句,但我觉得这样分开写可以让你更清楚地看到是怎么实现的。

撰写回答