Селен, наличие одного из множества элементов находится?

Построение ответа на вопрос Как дождаться загрузки страницы Selenium для Python? Я пытаюсь создать метод, который позволяет опрашивать присутствие нескольких элементов с использованием ожидаемых условий.

Я получаю сообщение об ошибке "объект bool" не вызывается в строке, содержащей: wait.until(любой (ожидания)).

Мысленный процесс состоял в том, чтобы позволить нескольким путям Xpath быть переданы в качестве ожидаемых условий, затем использовать any(), аналогично этому ответу на основе Java. Пытаясь дождаться одного из двух элементов на странице, используя selenium xpath, проверьте, любое из условий присутствует.

Как правильно использовать any() в этом случае? Или, еще лучше, что нужно сделать, чтобы этот метод работал?

Предположим, что Selenium .get('url') уже был выполнен непосредственно перед вызовом этого метода.

def wait_with_xpath_expectation(self, search_elements, timeout=6, max_attempts=3):
    """
    Selenium wait for an element(s) designated by Xpath to become available in the DOM. Useful for javascript AJAXy
    loading pages where content may be be rendered dynamically on the client side after page load appears complete.
    search_elements may be one Xpath as a string or many as a list. This allows for any of multiple elements on a
    page or pages to be determined to have loaded based on expectations.
    :param search_elements: string or list (strings converted to lists), Xpath(s)
    :param timeout: int, seconds
    :param max_attempts: int, time to wait before giving up on page loading
    :return: Boolean, True if page has loaded, False if all attempts have failed
    """

    # Page is not loaded yet
    loaded = False

    # Initialize attempt count
    attempt = 0

    # If only one element has been passed, ensure it is encapsulated by a list
    if type(search_elements) is str:
        search_elements = [search_elements]

    # Begin the polling loop
    while attempt < max_attempts:

        try:

            while loaded is False:
                # Create a list of expected elements using list comprehension
                expectations = [EC.presence_of_element_located((By.XPATH, element)) for element in search_elements]

                # Define wait
                wait = WebDriverWait(self.browser, timeout)

                # Execute
                wait.until(any(expectations))

                # Acknowledge load
                loaded = True

                print("Success: Page loaded based on expectations")

                # Exit returning True for load
                return loaded

        except TimeoutException as e:

            # Increment attempts
            attempt += 1

            # Check again if max attempts has not been exceeded
            while attempt < max_attempts:

                # Increase timeout by 20%
                timeout *= .2

                # Try again 
                continue

            # Print an error if max attempts is exceeded
            print("Error: Max load with expectations attempts exceeded,", e)

            # Exit returning False for load
            return loaded

2 ответа

У вас может быть ожидаемый класс условий для ожидания комбинации ожидаемых условий. Вот пример одного.

class wait_for_all(object):
    def __init__(self, methods):
        self.methods = methods

    def __call__(self, driver):
        try:
            for method in self.methods:
                if not method(driver):
                    return False
            return True
        except StaleElementReferenceException:
            return False

Затем это можно использовать, создав массив ожидаемых условий и проверив их все в одном и том же ожидании. (Примеры строк разделены для ясности.)

methods = []
methods.append(EC.visibility_of_element_located(BY.ID, "idElem1"))
methods.append(EC.visibility_of_element_located(BY.ID, "idElem2"))
method = wait_for_all(methods)
WebDriverWait(driver, 5).until(method)

Это выполнит одну пятисекундную задержку при проверке видимости двух разных элементов.

Я задокументировал это далее в блоге здесь.

Как только я понял, что у Xpath есть возможность объединения, работает следующий метод. Я оставлю этот ответ открытым, если у кого-то еще есть лучший ответ.

def wait_with_xpath_expectation(self, search_elements, timeout=6, max_attempts=3):
    """
    Selenium wait for an element designated by Xpath to become available in the DOM. Useful for javascript AJAXy
    loading pages where content may be be rendered dynamically on the client side after page load appears complete.
    search_elements may be one Xpath as a string or many as a list. This allows for any of multiple elements on a
    page or pages to be determined to have loaded based on expectations.
    :param search_elements: string or list (strings converted to lists), Xpath(s)
    :param timeout: int, seconds
    :param max_attempts: int, time to wait before giving up on page loading
    :return: Boolean, True if page has loaded, False if all attempts have failed
    """

    # Page is not loaded yet
    loaded = False

    # Initialize attempt count
    attempt = 0

    # If only one element has been passed, ensure it is encapsulated by a list
    if type(search_elements) is str:
        search_elements = [search_elements]

    # Begin the polling loop
    while attempt < max_attempts:

        try:

            while loaded is False:
                # Decompose the list of Xpaths to a union of nodes
                node_union = " | ".join(search_elements)

                expectation = EC.presence_of_element_located((By.XPATH, node_union))

                # Define wait
                wait = WebDriverWait(self.browser, timeout)

                # Execute
                wait.until(expectation)

                # Acknowledge load
                loaded = True

                print("Success: Page loaded based on expectations")

                # Exit returning True for load
                return loaded

        except TimeoutException as e:

            # Increment attempts
            attempt += 1

            # Check again if max attempts has not been exceeded
            while attempt < max_attempts:

                # Increase timeout by 20%
                timeout *= .2

                # Try again
                continue

            # Print an error if max attempts is exceeded
            print("Error: Max load with expectations attempts exceeded,", e)

            # Exit returning False for load
            return loaded
Другие вопросы по тегам