硒,是否存在众多元素之一?

时间:2018-08-01 20:09:25

标签: python selenium web-scraping expected-condition

How to wait until the page is loaded with Selenium for Python?的答案为基础,我试图创建一种方法,该方法允许使用“预期条件”来轮询多个元素的存在。

我在包含wait.until(any(expectations))的行上收到错误的'bool'对象不可调用

思考过程是允许将多个Xpath作为预期条件传递,然后以类似于基于Java的答案any()的方式使用Trying to wait for one of two elements in the page using 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 个答案:

答案 0 :(得分:1)

您可以具有一个预期条件类来等待预期条件的组合。这是一个例子。

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)

这将等待五秒钟,同时检查两个不同元素的可见性。

我在博客文章here中对此做了进一步的记录。

答案 1 :(得分:0)

一旦我意识到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