Selenium Expected Conditions - possible to use 'or'?

后端 未结 3 981
星月不相逢
星月不相逢 2020-12-01 06:23

I\'m using Selenium 2 / WebDriver with the Python API, as follows:

from selenium.webdriver.support import expected_conditions as EC

# code that causes an aj         


        
3条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-01 07:01

    Ancient question but,

    Consider how WedDriverWait works, in an example independent from selenium:

    def is_even(n):
        return n % 2 == 0
    
    x = 10
    
    WebDriverWait(x, 5).until(is_even)
    

    This will wait up to 5 seconds for is_even(x) to return True

    now, WebDriverWait(7, 5).until(is_even) will take 5 seconds and them raise a TimeoutException

    Turns out, you can return any non Falsy value and capture it:

    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
    

    Now consider how the methods of EC works:

    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
    

    You probably would want to try something like:

    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)
    

    this WOULD work if EC.presence_of_element_located returned False when selector not found in parent, but it raises an exception, an easy-to-understand workaround would be:

    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)
    

    My goal was to explain, artfulrobot already gave a snippet for general use of actual EC methods, just note that

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

    Is just a more flexible way to define functions (actually, a 'function-like', but that's irrelevant in this context)

提交回复
热议问题