WebDriverWait (self.driver, wait_time).until (EC.visibility_of_element_located ((by, locator))) 源码解析

本贴最后更新于 1559 天前,其中的信息可能已经东海扬尘

WebDriverWait(self.driver, wait_time).until(EC.visibility_of_element_located((by, locator)))源码的时候,不太明白visibility_of_element_located((by, locator))内为什么是两层括号,因为源码是这样写的:

class visibility_of_element_located(object):
    """ An expectation for checking that an element is present on the DOM of a
    page and visible. Visibility means that the element is not only displayed
    but also has a height and width that is greater than 0.
    locator - used to find the element
    returns the WebElement once it is located and visible
    """
    def __init__(self, locator):
        self.locator = locator
    def __call__(self, driver):
        try:
            return _element_if_visible(_find_element(driver, self.locator))
        except StaleElementReferenceException:
            return False

__call__()的作用是,让实例对象也像函数一样作为可调用对象来使用,正常来讲visibility_of_element_located(locator)(driver)才对,直到看了下until的源码,才发现有这一层:value = method(self._driver),其中这个method就是EC.visibility_of_element_located((by, locator))的实例对象,method(self._driver)就是EC.visibility_of_element_located((by, locator))(self._driver),也就是把实例对象作为参数一样传了个参数self._driver。其实前者((by, locator))__init__()做初始化,只不过参数是个元组(by, locator),这个元组作为实例对象的属性self.locator,而后者(self._driver)就是__call__()的作用

 def until(self, method, message=''):
        """Calls the method provided with the driver as an argument until the \
        return value is not False."""
        screen = None
        stacktrace = None
        end_time = time.time() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, 'screen', None)
                stacktrace = getattr(exc, 'stacktrace', None)
            time.sleep(self._poll)
            if time.time() > end_time:
                break
        raise TimeoutException(message, screen, stacktrace)

当使用EC.visibility_of_element_located((by, locator))(self._driver)时,总共进行了以下的步骤:

  1. 实例化一个EC.visibility_of_element_located,传入参数(by, locator),将其赋值给属性self.locator

  2. 通过__call__(),将参数self._driver(实际上这个self.driver就是WebDriverWait中的self.driver传进来的)和self.locator传给内层方法_find_element()

  2.1 这个find_element(self._driver, self.locator)对应着源码中的driverby,再通过*by解包(by, locator),使其这样调用driver.find_element(by, locator)

def _find_element(driver, by):
    """Looks up an element. Logs and re-raises ``WebDriverException``
    if thrown."""
    try:
        return driver.find_element(*by)
    except NoSuchElementException as e:
        raise e
    except WebDriverException as e:
        raise e

  2.2 然后driver.find_element(by, locator)找到元素对象并返回给_find_element()方法

  2.3 _find_element()方法拿到元素对象,此时作为参数传递给_element_if_visisble()方法,element_if_visisble()方法通过判断元素是否可见,返回TrueFalse

until作为一个判断条件,来决定是否继续寻找可见元素,主要有这几种情况:如果EC.visibility_of_element_located((by, locator))(self._driver)返回为True,则返回对应的True;如果已超时,则抛出超时异常
image.png

回帖
请输入回帖内容 ...