暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

简述Selenium 底层原理

1389

简单的聊聊selenium 底层的原理、不懂这些原理别说你懂自动化。。。。

一、首先实例化浏览器驱动实例:

在浏览器驱动实例selenium做了以下几件事

from selenium import webdriver
import logging
logging.basicConfig(level=logging.DEBUG)  # 打印源码中的日志
sp =webdriver.Chrome() #初始化Chrome类

复制

Chrome类

class WebDriver(RemoteWebDriver):
    # 继承至RemoteWebDriver类
    """
    Controls the ChromeDriver and allows you to drive the browser.

    You will need to download the ChromeDriver executable from
    http://chromedriver.storage.googleapis.com/index.html
    """


    def __init__(self, executable_path="chromedriver", port=0,
                 options=None, service_args=None,
                 desired_capabilities=None, service_log_path=None,
                 chrome_options=None, keep_alive=True)
:

        # executable_path 参数就是chromedriver 驱动的名字在后面会讲到为什么要默认为
  # chromedriver
        
        # 其他参数是对浏览器的一些配置这里不详细讲、executable_path参数才是启到关键
        
        
    .......
    
    # 这里做了一件启动服务的操作
    # Service类来自于:
    # .chrome.Service
    # 每个浏览器都有自己的驱动服务类
    self.service = Service(
            executable_path, # 为浏览器驱动程序
            port=port, # 获取的端口号
            service_args=service_args,
            log_path=service_log_path # 服务日志文件路径
    )
    
    # 开始启动webdriver 服务
    self.service.start()

        

复制

Service 类


Service 类主要是启动webdriver 本地服务的我们看看它内部做了哪些事情。

class Service(object):

    def __init__(self, executable, port=0, log_file=DEVNULL, env=None, start_error_message=""):
        self.path = executable # 是浏览器驱动程序路径、接收的就是上边的Chrome类
              #executable_path 传递过来的
 
        self.port = port # 服务的port 
        if self.port == 0:
            # 如果为默认的0 则进行绑定随机端口
            self.port = utils.free_port()


        if not _HAS_NATIVE_DEVNULL and log_file == DEVNULL:
            log_file = open(os.devnull, 'wb')

        self.start_error_message = start_error_message
        self.log_file = log_file # 日志文件
        self.env = env or os.environ # 获取系统全局变量(系统环境变量)

    @property
    def service_url(self):
        """
        Gets the url of the Service
        """

        # 对完整的webdriver http 服务进行拼接
        return "http://%s" % utils.join_host_port('localhost', self.port)

    def command_line_args(self):
        raise NotImplemented("This method needs to be implemented in a sub class")

    def start(self):
        """
        Starts the Service.

        :Exceptions:
         - WebDriverException : Raised either when it can't start the service
           or when it can't connect to the service
        """

        # 开始启动webdriver服务、下面操作其实就是执行了一个shell命令、windows上为dos命令
        try:
            cmd = [self.path] #拿到浏览器驱动程序
            cmd.extend(self.command_line_args())
            self.process = subprocess.Popen(cmd, #命令 
                                            env=self.env, # 全局变量
                                            close_fds=platform.system() != 'Windows',
                                            # 在windows下关闭dos窗口
                                            stdout=self.log_file,
                                            # 执行输出的内容
                                            stderr=self.log_file,
                                            # 执行时异常内容
                                            stdin=PIPE
                                            # 输入的内容
                                           )
        ........
        

复制


free_port方法

def free_port():
    """
    Determines a free port using sockets.
    """

    # 使用套接字来确定空闲端口
    free_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定一个随机的空闲端口
    free_socket.bind(('0.0.0.0'0))
    free_socket.listen(5)
    # 获取端口号
    port = free_socket.getsockname()[1]
    # 关闭socket服务
    free_socket.close()
    return port
        

复制



其实start方法就是在cmd 做了下面事情

这样就是启动了一个webdriver服务、端口是21111、我们其实可以在浏览器访问的。

127.0.0.1:21111

出现上面内容chromewebdriver 服务已经完成、下一步就selenium中的chrome方法实现的启动浏览器、在启动浏览器前selenium做了一件事就是创建一个session id 用于向webdriver服务发起http请求鉴权指令。

我们打开日志可以查看

http://127.0.0.1:52406/session  该http地址就是创建session 的接口地址、拿到这个session 后就可以在后续对浏览器进行操作、每个操作都是一个http请求、我们只需要启动webdriver服务知道对应的http 接口就可以直接对浏览器进行操作、selenium其实就是使用的webdriver的服务接口对底层进行了封装、暴露出的是封装后的各种语言版本的语法。

webdriver是一种协议、它规定了一组操作浏览器的规范、有了这个规范我们就可以使用不同语言进行封装各种浏览器操作。

其实懂了这些原理我们完全可以自行使用webdriver协议封装类似于selenium client 这样的工具包了。那么你是不是有一定的思路、且打开了对自动化测试的新认知呢?

总结

上面的源码不懂没关系、下面整体的大概总结一下你就懂了基本原理:


1、在我们初始化selenium时selenium client 会进行去启动chromewebdriver.exe(chrome/ie等) 驱动程序

2、浏览器驱动程序通过selenium生成的端口进行启动http webdriver服务、并进行绑定了一个随机的端口号

3、之后selenium client 向webdriver服务发起http请求(路径为http://127.0.0.1:port/session)从webdriver服务生成一个session ID

4、拿到session ID 后 webdriver会进行执行启动浏览器操作、浏览器启动后在每次的浏览器操作时 selenium client 都需要将该session ID 传递给webdriver 服务进行鉴权验证

5、之后每一个selenium 脚本操作都将进行发送指定的http请求到webdriver服务中、webdriver服务进行对指定的脚本操作进行执行、并将执行的结果以http接口 json数据传递给selenium 脚本、并将执行的日志成功或异常抛出到控制台中

我这里也要整理了一些webdriver http 接口

selenium封装的就是这些接口请求。。。



文章转载自测试前沿布道者,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论