【问题标题】:Selenium Expected Conditions - possible to use 'or'?Selenium 预期条件 - 可以使用“或”吗?
【发布时间】:2013-05-03 22:51:51
【问题描述】:

我正在使用 Selenium 2 / WebDriver 和 Python API,如下:

from selenium.webdriver.support import expected_conditions as EC

# code that causes an ajax query to be run

WebDriverWait(driver, 10).until( EC.presence_of_element_located( \
    (By.CSS_SELECTOR, "div.some_result")));

我想等待或者返回结果 (div.some_result)“未找到”字符串。那可能吗?种类:

WebDriverWait(driver, 10).until( \
    EC.presence_of_element_located( \
         (By.CSS_SELECTOR, "div.some_result")) \
    or 
    EC.presence_of_element_located( \
         (By.CSS_SELECTOR, "div.no_result")) \
);

我意识到我可以使用 CSS 选择器 (div.no_result, div.some_result) 来做到这一点,但是有没有办法使用 Selenium 预期条件方法来做到这一点?

【问题讨论】:

标签: python selenium


【解决方案1】:

我是这样做的:

class AnyEc:
    """ Use with WebDriverWait to combine expected_conditions
        in an OR.
    """
    def __init__(self, *args):
        self.ecs = args
    def __call__(self, driver):
        for fn in self.ecs:
            try:
                res = fn(driver)
                if res:
                    return True
                    # Or return res if you need the element found
            except:
                pass

那就这样称呼吧……

from selenium.webdriver.support import expected_conditions as EC
# ...
WebDriverWait(driver, 10).until( AnyEc(
    EC.presence_of_element_located(
         (By.CSS_SELECTOR, "div.some_result")),
    EC.presence_of_element_located(
         (By.CSS_SELECTOR, "div.no_result")) ))

显然,同样实现AllEc 类也很简单。

铌。 try: 块是奇数。我很困惑,因为有些 EC 返回 true/false,而其他 EC 会抛出 NoSuchElementException 为 False。异常被 WebDriverWait 捕获,所以我的 AnyEc 事情产生了奇怪的结果,因为第一个抛出异常意味着 AnyEc 没有进行下一个测试。

【讨论】:

  • 很好的解决方案@artfulrobot!但是,这会降低 fn() 的返回值,即找到的元素。将其更改为 "res = fn(driver); if res: return res" 就可以了。
  • 关于 NB 部分的小补充 .. EC 将在使用 present_of_all_elements_located 时返回 False ,因为它会返回一个空列表 .. 另一方面,它会在 present_of_element_located 上抛出异常,因为它不能使用列表。至少这是我在测试时注意到的。顺便说一句,很好的解决方案!
【解决方案2】:

古老的问题,但是,

考虑WedDriverWait 的工作原理,在一个独立于 selenium 的示例中:

def is_even(n):
    return n % 2 == 0

x = 10

WebDriverWait(x, 5).until(is_even)

这将等待 is_even(x) 返回 True 最多 5 秒

现在,WebDriverWait(7, 5).until(is_even) 将需要 5 秒,然后它们会引发 TimeoutException

事实证明,您可以返回任何非 Falsy 值并捕获它:

def return_if_even(n):
    if n % 2 == 0:
        return n
    else:
        return False

x = 10
y = WebDriverWait(x, 5).until(return_if_even)
print(y) # >> 10

现在考虑EC 的方法是如何工作的:

print(By.CSS_SELECTOR) # first note this is only a string
>> 'css selector'

cond = EC.presence_of_element_located( ('css selector', 'div.some_result') )
# this is only a function(*ish), and you can call it right away:

cond(driver)
# if element is in page, returns the element, raise an exception otherwise

您可能想尝试以下方法:

def presence_of_any_element_located(parent, *selectors):
    ecs = []
    for selector in selectors:
        ecs.append(
            EC.presence_of_element_located( ('css selector', selector) )
        )

     # Execute the 'EC' functions agains 'parent'
     ecs = [ec(parent) for ec in ecs]

     return any(ecs)

如果EC.presence_of_element_locatedselector 中找不到parent 时返回False,这将起作用,但它会引发异常,一个易于理解的解决方法是:

def element_in_parent(parent, selector):
    matches = parent.find_elements_by_css_selector(selector)
    if len(matches) == 0:
        return False
    else:
        return matches

def any_element_in_parent(parent, *selectors):
    for selector in selectors:
        matches = element_in_parent(parent, selector)
        # if there is a match, return right away
        if matches:
            return matches
    # If list was exhausted
    return False

# let's try 
any_element_in_parent(driver, 'div.some_result', 'div.no_result')
# if found in driver, will return matches, else, return False

# For convenience, let's make a version wich takes a tuple containing the arguments (either one works):
cond = lambda args: any_element_in_parent(*args)
cond( (driver, 'div.some_result', 'div.no_result') )
# exactly same result as above

# At last, wait up until 5 seconds for it 
WebDriverWait((driver, 'div.some_result', 'div.no_result'), 5).until(cond)

我的目标是解释,artfulrobot 已经给出了一个 sn-p 用于实际 EC 方法的一般用途,请注意

class A(object):
    def __init__(...): pass
    def __call__(...): pass

只是定义函数的一种更灵活的方式(实际上是“类函数”,但在这种情况下无关紧要)

【讨论】:

    【解决方案3】:

    不完全通过 EC,但确实达到了相同的结果 - 有奖金。
    仍然使用WebDriverWaituntil() 方法,但在lambda 表达式中传递纯find_elements_*() 方法:

    WebDriverWait(driver, 10).until(lambda driver: driver.find_elements_by_id("id1") or \
                                                   driver.find_elements_by_css_selector("#id2"))[0]
    

    find_elements_*() 方法返回所有匹配元素的列表,如果没有匹配元素,则返回一个空元素 - 这是一个布尔值 false。因此,如果第一个调用没有找到任何东西,则评估第二个;重复直到他们中的任何一个找到匹配项,或者时间用完。

    奖励 - 当它们返回值时,最后的索引 [0] 实际上会返回匹配的元素 - 如果你有任何用处,在后续调用中。

    【讨论】:

    • 真正的pythonic版本的ExpectedCondition.or in selenium Java
    猜你喜欢
    • 2022-01-22
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 2021-08-16
    • 2020-05-04
    • 1970-01-01
    相关资源
    最近更新 更多