Selenio Condiciones esperadas: ¿se puede usar ‘o’?

Estoy usando Selenium 2 / WebDriver con la API de Python, de la siguiente manera:

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"))); 

Quiero esperar a que se devuelva un resultado ( div.some_result ) o una cadena “No encontrado”. ¿Es eso posible? Mas o menos:

 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")) \ ); 

Me doy cuenta de que podría hacer esto con un selector de CSS ( div.no_result, div.some_result ), pero ¿hay alguna forma de hacerlo utilizando el método de condiciones esperadas de Selenium?

Lo hice así:

 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: if fn(driver): return True except: pass 

Entonces llámalo como …

 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")) )) 

Obviamente, sería trivial implementar también una clase AllEc la misma manera.

Nótese bien. El try: bloque es impar. Estaba confundido porque algunas EC devuelven verdadero / falso, mientras que otros arrojarán excepciones por Falso. WebDriverWait detectó las excepciones, por lo que mi cosa de AnyEc estaba produciendo resultados extraños porque la primera en lanzar una excepción significaba que AnyEc no pasaba a la siguiente prueba.

Antigua pregunta pero

Considere cómo funciona WedDriverWait , en un ejemplo independiente de selenium:

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

Esto esperará hasta 5 segundos para que is_even(x) devuelva True

ahora, WebDriverWait(7, 5).until(is_even) tomará 5 segundos y ellos generarán una TimeoutException

Resulta que, puedes devolver cualquier valor que no sea Falsy y capturarlo:

 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 

Ahora considere cómo funcionan los métodos de 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 

Probablemente quieras probar algo como:

 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) 

esto funcionaría si EC.presence_of_element_located devolviera False cuando el selector no se encuentra en el elemento parent , pero genera una excepción, una solución fácil de entender sería:

 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 sel 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: 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) 

Mi objective era explicar, artfulrobot ya dio un fragmento para el uso general de los métodos EC reales, solo tenga en cuenta que

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

Es solo una forma más flexible de definir funciones (en realidad, es ‘similar a una función’, pero eso es irrelevante en este contexto)

Trate de usar la expresión lambda:

WebDriverWait(driver, 10).until(lambda a:
a.presence_of_element_located(By.CSS_SELECTOR, "div.some_result") OR a.presence_of_element_located(By.CSS_SELECTOR, "div.no_result"))