Python Selenium: ожидание загрузки одного элемента ИЛИ другого элемента

Я использую этот код для ожидания загрузки элемента:

browser = webdriver.Chrome(executable_path=chromedriver,options=ChromeOpts, desired_capabilities=captain) 
wait = WebDriverWait(browser, 5)
openbrowser = browser.get(url) 
wait.until(EC.presence_of_element_located((By.ID, 'h1')))
browser.execute_script("window.stop();")

Однако мне действительно нужно дождаться одного элемента ИЛИ другого. Так что я могу, например, дождаться «h1» ИЛИ «rf-footer».

Благодарность,


person rafasalo    schedule 05.01.2019    source источник


Ответы (3)


Вы можете объединить две проверки в одной wait() операции - используя лямбда-выражение Python, используя find_elements_*() методы, склеенные вместе с or:

element = wait.until(lambda x: x.find_elements_by_id("id1") or x.find_elements_by_css_selector("#id2"))[0]

Вы можете использовать этот подход даже для получения элемента, который соответствует первому - [0] в конце.
Это решение работает, поскольку find_elements_*() возвращает список всех согласованных элементов или пустой, если таковых нет ( логическое значение false). Итак, если первый вызов ничего не находит, выполняется второй; это повторяется до тех пор, пока один из них не найдет совпадение или пока не истечет время.

Такой подход дает то преимущество, что wait.until() останавливается сразу после одного из двух проходов - например, скорость.


В отличие от блока try-catch - в нем первое условие должно завершиться неудачно (ожидалось до X секунд, обычно 10), а второе даже должно быть проверено; поэтому, если первое ложно, а второе истинно - время выполнения / ожидания будет составлять не менее X секунд плюс время, которое займет вторая проверка.
В худшем случае, когда оба значения ложны, вы попадаете в 2X подождите, по сравнению с X в сочетании двух. Если вы добавляете другие условия, вы только увеличиваете коэффициент.

person Todor Minakov    schedule 05.01.2019
comment
Спасибо!! Я попробовал первый и получил: AttributeError: 'WebDriver' object has no attribute 'presence_of_element_located' - person rafasalo; 05.01.2019
comment
Есть идеи по ее решению? - person rafasalo; 05.01.2019
comment
Мой плохой, толстопалый на мобиле (тоже сейчас скрестив пальцы :). Проблема заключалась в том, что presence_of_element_located() - это класс в expected_conditions, а не метод объекта webdriver (который является x в лямбда-выражении). - person Todor Minakov; 05.01.2019
comment
Теперь происходит еще одно исключение. После выполнения: browser.execute_script("return document.documentElement.outerHTML") Я получаю: selenium.common.exceptions.WebDriverException: Message: unknown error: Cannot read property 'outerHTML' of null Когда я пытаюсь получить HTML, кажется, что он возвращает null. - person rafasalo; 05.01.2019
comment
Мой код: browser = webdriver.Chrome(executable_path=chromedriver, options=ChromeOpts, desired_capabilities=capa) wait = WebDriverWait(browser, 10) openbrowser = browser.get(url) #navigate to the page a = wait.until(lambda x: EC.presence_of_element_located((By.ID, "id_max")) or EC.presence_of_element_located((By.ID, "max_id"))) browser.execute_script("window.stop();") html = browser.execute_script("return document.documentElement.outerHTML") BTW, уже изменен на innerHTML. Я вижу на консоли, что до того, как страница перестает загружаться, консоль уже завершена для запуска кода. - person rafasalo; 05.01.2019
comment
Я думаю, что понял, я поставил time.sleep(x) перед запуском последнего скрипта. - person rafasalo; 05.01.2019
comment
Часть с expected_conditions неверна, потому что ec.presence_of_element_located возвращает объект, и поэтому использование оператора or всегда будет возвращать часть до or, но часть после or никогда не будет выполнена. - person Jakub Bláha; 16.05.2020
comment
@ JakubBláha, вы правы, это не сработает - но по другой причине. Первый presence_of_element_located(), когда элемента нет, не вернет объект, но вызовет исключение, которое перехватывается wait.until(), и цикл повторяется. Таким образом, второй presence_of_element_located() фактически никогда не будет выполнен - ​​это та часть, в которой вы правы. Я отредактирую ответ, оставив только find_elements*() - это всегда будет работать, как если бы ничего не было найдено, они возвращают пустой список (логическое значение false). - person Todor Minakov; 16.05.2020
comment
Но какое исключение это вызовет? На самом деле он ничего не делает, пока не будет вызван методом until, поэтому он не может вызвать никаких исключений. Второй объект даже не был создан. Спасибо за редактирование ответа и спасибо за фактическое рабочее решение. - person Jakub Bláha; 17.05.2020
comment
Он вызывает ElementNotFound, который обрабатывается блоком catch until(). - person Todor Minakov; 18.05.2020

Вы можете сделать это, используя expected_conditions

from selenium.webdriver.support import expected_conditions

полное решение можно найти здесь: Ожидаемые условия селена - можно использовать 'или' ?

person Califlower    schedule 05.01.2019
comment
Спасибо! Я купил его с помощью TRY / EXCEPT. openbrowser = browser.get(url) #navigate to the page try: wait.until(EC.presence_of_element_located((By.ID, id_stop))) except: wait.until(EC.presence_of_element_located((By.ID, 'rf-footer'))) browser.execute_script("window.stop();") - person rafasalo; 05.01.2019

Я купил его с помощью TRY / EXCEPT.

openbrowser = browser.get(url) #navigate to the page 
try: 
   wait.until(EC.presence_of_element_located((By.ID, id_stop))) 
except: 
   wait.until(EC.presence_of_element_located((By.ID, 'rf-footer')))
browser.execute_script("window.stop();")
person rafasalo    schedule 05.01.2019