selenium学习(三)

本文详细解读了Selenium源码中的remote目录、webdriver模块、公共模块如alert、action_chains和expected_conditions的使用,以及support目录中的事件监听和颜色处理功能。
摘要由CSDN通过智能技术生成

本节继续进行selenium源码学习,上一节介绍了浏览器对应得模块,本节记录公共模块

目录

一、remote目录

1.remote_connection.py

2.webdriver.py

(1)元素相关

(2)窗口相关 

(3) 截图相关

(4) cookie相关

3.switch_to.py 

4.webelement.py 

二、common目录

1.alert.py

2.action_chains.py

3.By.py 

 4.Key.py

三、support目录

 1.abstract_event_listener.py

2.color.py

3.expected_conditions.py

(1)title相关

(2)url相关

(3)元素相关

4.wait.py


一、remote目录

1.remote_connection.py

这个模块主要包含其他浏览器remote模块继承类RemoteConnection

包含一个全局类变量_timeout,用于标记链接超时时间,使用得是python socket库中全局默认超时时间

_timeout = socket._GLOBAL_DEFAULT_TIMEOUT

关于这个类全局变量包含四个函数,其中函数中得cls表示Class,与self不同,self参数需要创建类对象后方可使用,cls则表示类本身,所以可以不用创建对象直接调用

    @classmethod
    def get_timeout(cls):
        """
        :Returns:
            Timeout value in seconds for all http requests made to the Remote Connection
        """
        return None if cls._timeout == socket._GLOBAL_DEFAULT_TIMEOUT else cls._timeout

    @classmethod
    def set_timeout(cls, timeout):
        """
        Override the default timeout

        :Args:
            - timeout - timeout value for http requests in seconds
        """
        cls._timeout = timeout

    @classmethod
    def reset_timeout(cls):
        """
        Reset the http request timeout to socket._GLOBAL_DEFAULT_TIMEOUT
        """
        cls._timeout = socket._GLOBAL_DEFAULT_TIMEOUT

    @classmethod
    def get_remote_connection_headers(cls, parsed_url, keep_alive=False):
        """
        Get headers for remote request.

        :Args:
         - parsed_url - The parsed url
         - keep_alive (Boolean) - Is this a keep-alive connection (default: False)
        """

        system = platform.system().lower()
        if system == "darwin":
            system = "mac"

        headers = {
            'Accept': 'application/json',
            'Content-Type': 'application/json;charset=UTF-8',
            'User-Agent': 'selenium/{} (python {})'.format(__version__, system)
        }

        if parsed_url.username:
            base64string = base64.b64encode('{0.username}:{0.password}'.format(parsed_url).encode())
            headers.update({
                'Authorization': 'Basic {}'.format(base64string.decode())
            })

        if keep_alive:
            headers.update({
                'Connection': 'keep-alive'
            })

        return headers

2.webdriver.py

包含WebDriver类也就是其他浏览器所继承的模块,对于该类的参数以及初始化讲解在selenium学习(二)中以及提到过,就不详细介绍了,主要介绍有哪些函数

(1)元素相关

首先就是搜索元素的方法,也就是八种类型对应每个类型两种的方法,一个返回一个,一个返回列表

    def find_element_by_id(self, id_):
        return self.find_element(by=By.ID, value=id_)

    def find_elements_by_id(self, id_):
        return self.find_elements(by=By.ID, value=id_)

(2)窗口相关 

窗口相关的操作有尺寸、多窗口切换、刷新、前进后退等

例如:

# 执行当前窗口刷新操作,等于左上角刷新/F5
driver.refresh()
# 执行当前窗口的前进/后退操作,等于左上角的前进/后退
driver.forward()
driver.back()
# 执行窗口的切换,本质调用的都是driver.switch_to(),且用的是switch_to.py模块,后续介绍
driver.switch_to_alret()
driver.switch_to_window()
# 获取当前web对象包含的windows列表
driver.window_handles()
此时就可以通过连用,例如:
# 切换到第0个窗口
lists = driver.window_handles()
driver.switch_to_window(lists[0])
# 还有获取尺寸、放大、缩小等操作
driver.maximize_window()
driver.minimize_window()
driver.get_window_size(lists[0])
driver.set_window_size('111', '111')

(3) 截图相关

# 截图当前页面,并保存,save_screenshot本质调用的也是get_screenshot_as_file
driver.get_screenshot_as_file(filename)
driver.save_screenshot()
# 截图当前页面,并且转化为ascii
driver.get_screenshot_as_png()
driver.get_screenshot_as_base64()

(4) cookie相关

# 获取所有的cookie或者指定的cookie
driver.get_cookies()
driver.get_cookie(name)
# 添加对应的cookie
driver.add_cookie(cookie_dict)
# 删除所有cookie或者指定cookie
driver.delete_all_cookies()
driver.delete_cookie(name)

3.switch_to.py 

包含SwitchTo类,主要作用是切换浏览器下的各个窗口

    @property
    def alert(self):
        alert = Alert(self._driver)
        alert.text
        return alert

    def default_content(self):
        self._driver.execute(Command.SWITCH_TO_FRAME, {'id': None})

    def frame(self, frame_reference):
        if isinstance(frame_reference, basestring) and self._driver.w3c:
            try:
                frame_reference = self._driver.find_element(By.ID, frame_reference)
            except NoSuchElementException:
                try:
                    frame_reference = self._driver.find_element(By.NAME, frame_reference)
                except NoSuchElementException:
                    raise NoSuchFrameException(frame_reference)

        self._driver.execute(Command.SWITCH_TO_FRAME, {'id': frame_reference})

    def parent_frame(self):
        self._driver.execute(Command.SWITCH_TO_PARENT_FRAME)

    def window(self, window_name):
        if self._driver.w3c:
            self._w3c_window(window_name)
            return
        data = {'name': window_name}
        self._driver.execute(Command.SWITCH_TO_WINDOW, data)

4.webelement.py 

当你获取到一个元素时返回的就是WebElement这个对象,主要对这个对象进行一系列的操作获取爬取对应的类型,介绍常用的

# 进行元素点击
element.click()
# 判断元素是否被选中,主要用于复选框/勾选框等
element.is_selected()
# 判断元素是否启用
element.is_enabled()
# 返回元素的li tag列表,一般常用于ul下的li遍历,同样也包含八种16个函数
element.find_elements_by_tag_name('li')
# 对元素进行输入操作,一般用户input标签
element.send_keys('input')
# 获取元素的属性一般有以下两种方法
# 区别在于get_attribute一般用于获取编写html时输入的属性
# get_property一般用于获取编写html加载时DOM树生成的属性
# 不过目前基本大部分都是交合的,所以都可以使用
element.get_property('input')
element.get_attribute('input')

二、common目录

介绍部分常用模块

1.alert.py

Alert模块,控制浏览器的弹窗,初始化只需传入web对象

常用的有一个text属性,获取弹窗信息

    @property
    def text(self):
        """
        Gets the text of the Alert.
        """
        if self.driver.w3c:
            return self.driver.execute(Command.W3C_GET_ALERT_TEXT)["value"]
        else:
            return self.driver.execute(Command.GET_ALERT_TEXT)["value"]

还有弹窗的接受accept以及取消dismiss,如果有输入框的弹窗还有send_keys函数

    def accept(self):
        """
        Accepts the alert available.

        Usage::
        Alert(driver).accept() # Confirm a alert dialog.
        """
        if self.driver.w3c:
            self.driver.execute(Command.W3C_ACCEPT_ALERT)
        else:
            self.driver.execute(Command.ACCEPT_ALERT)

2.action_chains.py

包含类ActionChains主要用户实现元素的操作,初始化函数如下

    def __init__(self, driver):
        """
        Creates a new ActionChains.

        :Args:
         - driver: The WebDriver instance which performs user actions.
        """
        self._driver = driver
        self._actions = []
        if self._driver.w3c:
            self.w3c_actions = ActionBuilder(driver)

 perform函数表示执行所有的存储操作,后续举例时介绍

reset_actions函数则表示清空所有存储的操作

click函数表示执行点击

click_and_hold表示长按

等等各类鼠标操作,这里就不一一举例了,可以自行查看

例如:

ActionChains(driver).move_to_element(el).click().pause(1).send_keys('input').pause(1).perform()
# 表示先移动到el元素然后点击,等待一秒后输入input再等待一秒,这是存储的所有操作
# 最后添加perform()则进行存储释放,执行上述描述的步骤

3.By.py 

By类,主要用户元素爬取时对应的方法,也就是我们常说的八种爬取类型,使用时直接By.ID即可

class By(object):
    """
    Set of supported locator strategies.
    """

    ID = "id"
    XPATH = "xpath"
    LINK_TEXT = "link text"
    PARTIAL_LINK_TEXT = "partial link text"
    NAME = "name"
    TAG_NAME = "tag name"
    CLASS_NAME = "class name"
    CSS_SELECTOR = "css selector"

 4.Key.py

Key类,主要存放键盘特殊的输入,使用时直接调用即可

class Keys(object):
    """
    Set of special keys codes.
    """

    NULL = '\ue000'
    CANCEL = '\ue001'  # ^break
    HELP = '\ue002'
    BACKSPACE = '\ue003'
    BACK_SPACE = BACKSPACE

例如:

ActionChains(driver).move_to_element(el).send_keys(By.ENTER).perform()
# 表示先移动到el元素然后输入回车

三、support目录

介绍部分常用模块

 1.abstract_event_listener.py

该模块只包含一个类AbstractEventListener,主要用于事件侦听器,但是类中所有得方法均未实现,所以需要进行继承后挑选需要得部分进行实现

class AbstractEventListener(object):
    """
    Event listener must subclass and implement this fully or partially
    """

    def before_navigate_to(self, url, driver):
        pass

    def after_navigate_to(self, url, driver):
        pass

    def before_navigate_back(self, driver):
        pass

    def after_navigate_back(self, driver):
        pass

2.color.py

该模块下包含一个Color类、匹配各类颜色字符得正则以及一个Colors字典,存储常用得颜色类型

用于显示颜色。输入一定得可解析得文本,例如‘#00ff33’/rgb(0, 255, 51)/'blue'

正则匹配分为RGB/RGBA/HEX/HEX3/HSL/HSLA

RGB_PATTERN = r"^\s*rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)\s*$"
RGB_PCT_PATTERN = r"^\s*rgb\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*\)\s*$"
RGBA_PATTERN = r"^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0\.\d+)\s*\)\s*$"
RGBA_PCT_PATTERN = r"^\s*rgba\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(0|1|0\.\d+)\s*\)\s*$"
HEX_PATTERN = r"#([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})"
HEX3_PATTERN = r"#([A-Fa-f0-9])([A-Fa-f0-9])([A-Fa-f0-9])"
HSL_PATTERN = r"^\s*hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)\s*$"
HSLA_PATTERN = r"^\s*hsla\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*,\s*(0|1|0\.\d+)\s*\)\s*$"

Color类中,初始化一般接受四个函数,r,g,b,a

    def __init__(self, red, green, blue, alpha=1):
        self.red = int(red)
        self.green = int(green)
        self.blue = int(blue)
        self.alpha = "1" if float(alpha) == 1 else str(float(alpha) or 0)

主要使用得是静态form_string(str_)方法(匹配得过长,可自行前往源码查看)

@staticmethod
def from_string(str_):
   import re

   class Matcher(object):
        def __init__(self):
           self.match_obj = None

        def match(self, pattern, str_):
           self.match_obj = re.match(pattern, str_)
           return self.match_obj

        @property
        def groups(self):
           return () if self.match_obj is None else self.match_obj.groups()

     m = Matcher()

例如:调用Color.from_string("rgba(11, 22, 33, 0.1)").rgba,此时开始执行匹配机制

执行上面列出来得所有匹配,当匹配返回不为空时再执行对应返回,返回得均为Color得对象

        if m.match(RGB_PATTERN, str_):
            return Color(*m.groups)
        elif m.match(RGB_PCT_PATTERN, str_):
            rgb = tuple([float(each) / 100 * 255 for each in m.groups])
            return Color(*rgb)
        elif m.match(RGBA_PATTERN, str_):
            return Color(*m.groups)
        elif m.match(RGBA_PCT_PATTERN, str_):
            rgba = tuple([float(each) / 100 * 255 for each in m.groups[:3]] + [m.groups[3]])
            return Color(*rgba)
        elif m.match(HEX_PATTERN, str_):
            rgb = tuple([int(each, 16) for each in m.groups])
            return Color(*rgb)
        elif m.match(HEX3_PATTERN, str_):
            rgb = tuple([int(each * 2, 16) for each in m.groups])
            return Color(*rgb)
        elif m.match(HSL_PATTERN, str_) or m.match(HSLA_PATTERN, str_):
            return Color._from_hsl(*m.groups)
        elif str_.upper() in Colors.keys():
            return Colors[str_.upper()]
        else:
            raise ValueError("Could not convert %s into color" % str_)

此时后缀.rgba则表示该对象得rgba属性,包含如下三种

@property
def rgb(self):
    return "rgb(%d, %d, %d)" % (self.red, self.green, self.blue)

@property
def rgba(self):
    return "rgba(%d, %d, %d, %s)" % (self.red, self.green, self.blue, self.alpha)

@property
def hex(self):
    return "#%02x%02x%02x" % (self.red, self.green, self.blue)

最后会打印如下

from selenium.webdriver.support.color import Color
print(Color.from_string("rgba(11, 22, 33, 0.1)").rgba)

>rgba(11, 22, 33, 0.1)

3.expected_conditions.py

该模块主要用于判断,例如元素是否可点击,页面标题是否为需求字符等等类型

(1)title相关

title_is用于判断当前页面得title,也就是html中head里面得title,返回self.title == driver.title

例如:

import selenium
from selenium.webdriver.support import expected_conditions
web_driver = selenium.webdriver.Chrome()
web_driver.get("https://mp.csdn.net/")
print(expected_conditions.title_is('首页-CSDN博客')(web_driver))

>True

类似还有一个title_contains,不过返回的是self.title in driver.title

(2)url相关

url_to_be用于判断当前页面得url是否与输入得一致,返回self.url == driver.current_url

url_changes则与之相反,判断是否是不一致

url_matches则匹配浏览器得url中是否包含输入得正则,返回match is not None

url_contains则判断是否包含输入字符

例如:

import selenium
from selenium.webdriver.support import expected_conditions
web_driver = selenium.webdriver.Chrome()
web_driver.get("https://mp.csdn.net/")
print(expected_conditions.url_to_be("https://mp.csdn.net/")(web_driver))

# 这里是False是因为CSDN没有登录得情况下会默认跳转到登陆页面,所以url不为输入得
>False

(3)元素相关

剩余就不一一举例了,与元素相关得如果找到元素就返回元素,否则就返回false

    """
    方法	描述
    title_is(‘百度一下’)	判断当前页面的 title 是否等于预期
    title_contains(‘百度’)	判断当前页面的 title 是否包含预期字符串
    presence_of_element_located(locator)	判断元素是否被加到了 dom 树里,并不代表该元素一定可见
    visibility_of_element_located(locator)	判断元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0
    text_to_be_present_in_element_attribute(locator,attribute,text)
    visibility_of(element)	跟上一个方法作用相同,但传入参数为 element
    text_to_be_present_in_element(locator , ‘百度’)	判断元素中的 text 是否包含了预期的字符串
    text_to_be_present_in_element_value(locator , ‘某值’)	判断元素中的 value 属性是否包含了预期的字符串
    frame_to_be_available_and_switch_to_it(locator)	判断该 frame 是否可以 switch 进去,True 则 switch 进去,反之 False
    invisibility_of_element_located(locator)	判断元素中是否不存在于 dom 树或不可见
    element_to_be_clickable(locator)	判断元素中是否可见并且是可点击的
    staleness_of(element)	等待元素从 dom 树中移除
    element_to_be_selected(element)	判断元素是否被选中,一般用在下拉列表
    element_selection_state_to_be(element, True)	判断元素的选中状态是否符合预期,参数 element,第二个参数为 True/False
    element_located_selection_state_to_be(locator, True)	跟上一个方法作用相同,但传入参数为 locator
    alert_is_present()	判断页面上是否存在 alert
    """

4.wait.py

包含WebDriverWait类,主要用于web操作的等待判断,包含两个函数until以及until_not,一个表示内容是否存在,一个表示内容是否不存在初始化函数如下,接受参数

driver:操控的web对象

timeout:等待时间

poll_frequency:轮询间隔时间,默认为0.5

ignored_exceptions:忽略的错误类型,接受类型为元组,碰到该错误时提示为Timeout错误,也就是超时未检测到,

默认忽略NoSuchElementException

    def __init__(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None):
        self._driver = driver
        self._timeout = timeout
        self._poll = poll_frequency
        # avoid the divide by zero
        if self._poll == 0:
            self._poll = POLL_FREQUENCY
        exceptions = list(IGNORED_EXCEPTIONS)
        if ignored_exceptions is not None:
            try:
                exceptions.extend(iter(ignored_exceptions))
            except TypeError:  # ignored_exceptions is not iterable
                exceptions.append(ignored_exceptions)
        self._ignored_exceptions = tuple(exceptions)

until函数

    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)

举例:

WebDriverWait(driver, 20, 2).until(expected_conditions.alert_is_present())

表示在20s内每隔2s进行一次轮询,直到出现弹窗则结束,20s未出现弹窗则提示TimeoutException

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值