2013-05-09 2 views
13

Я использую Selenium 2/WebDriver с API Python, следующим образом:Selenium Ожидаемые условия - можно использовать «или»?

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) или с "Not Found" строка , Это возможно? Вид:

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 ожидаемого метода условия?

+0

взгляните на это http://stackoverflow.com/questions/7781792/selenium- waitforelement, может вам помочь .. –

+0

Класс ExpectedConditions является опрятным, но я узнал, что он не очень надежный сам по себе (в чистом виде), и вам нужно явно улавливать условия исключения, связанные с его использованием, а иногда и цикл повторите попытку. – djangofan

ответ

12

Я сделал это так:

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 

Затем вызовите его, как ...

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 класс также.

Nb. блок try: является нечетным. Я был смущен, потому что некоторые EC возвращают true/false, в то время как другие будут генерировать исключения для False. Исключения пойманы WebDriverWait, поэтому моя вещь AnyEc создавала нечетные результаты, потому что первая, которая выбрала исключение, означала, что AnyEc не перешел к следующему тесту.

-2

Try выражение использование лямбда:

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

1

Древний вопрос, но,

Рассмотрим, как WedDriverWait работы, в качестве примера независимые от селена:

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

x = 10 

WebDriverWait(x, 5).until(is_even) 

Это будет подождите до 5 секунд для is_even(x) вернуть True

сейчас, 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_located вернулся False когда selector не найден в parent, но это вызывает исключение, легкий для понимания обходной путь будет:

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) 

Моя цель состояла в том, чтобы объяснить, artfulrobot уже дал сниппет для общего использования фактических EC методов, просто отметим, что

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

Это всего лишь более гибкий способ определения функций (на самом деле, «функция-как», но в этом контексте это не имеет значения)

Смежные вопросы