• Selenium实现原理


    Selenium 是目前主流的用于Web应用程序测试的工具,可以直接运行在浏览器中,就像真正的用户在操作一样。

    selenium的实现原理是这样的:

    1.运行代码,启动浏览器后,webdriver会将浏览器绑定到特定端口,作为webdriver的remote server;
    2.Client(也就是测试脚本)借助ComandExecutor创建sessionId,发送HTTP请求(包括HTTP method, body)给remote server;
    3.remote server收到HTTP请求后,调用webdriver完成操作,并将HTTP响应的结果返回给Client。

    Selenium工作的过程中有三个角色,

    其一便是跟我们最近的自动化测试代码:自动化测试代码发送请求给浏览器的驱动

    其二便是浏览器的驱动:每个浏览器都有自己的驱动,均以exe文件形式存在,比如谷歌的chromedriver.exe、火狐的geckodriver.exe、IE的IEDriverServer.exe,

    它来解析这些自动化测试的代码,解析后把它们发送给浏览器;

    其三便是浏览器:执行浏览器驱动发来的指令,并最终完成工程师想要的操作

    下面以谷歌浏览器为例:

    首先,selenium client 会初始化一个 service 服务,通过 Webdriver 启动浏览器驱动程序 chromedriver.exe

    接着通过 RemoteWebDriver 向浏览器驱动程序发送 HTTP 请求,浏览器驱动程序解析请求,并获得 sessionId,如果再次对浏览器操作需携带此 id

    接下来打开浏览器,绑定特定的端口,把启动后的浏览器作为 Webdriver 的Remote Server

    打开浏览器后,每一条 Selenium 脚本,一个 http 请求会被创建并且发送给浏览器,浏览器执行具体的测试步骤后再将步骤执行结果返回给 Remote Server,Remote Server 又将结果返回给 Selenium 的脚本,如果是错误的 http 代码我们就会在控制台看到对应的报错信息。

    WebDriver 和 Selenium-Server 区别

    你可能需要,也可能不需要 Selenium Server,取决于你打算如何使用 Selenium-WebDriver。

    如果你仅仅需要使用 WebDriver API,那就不需要 Selenium-Server。

    如果你所有的测试和浏览器都在一台机器上,那么你仅需要 WebDriver API。WebDriver 将直接操作浏览器。

    在有些情况下,你需要使用 Selenium-Server 来配合 Selenium-WebDriver 工作,例如:
    你使用 Selenium-Grid 来分发你的测试给多个机器或者虚拟机。
    你希望连接一台远程的机器来测试一个特定的浏览器。
    你没有使用 Java 绑定(例如 Python, C#, 或 Ruby),并且可能希望使用 HtmlUnit Driver。

    底层实现原理

    下面先写一个通过火狐浏览器启动百度首页的脚本:

    from selenium import webdriver
    import logging

    logging.basicConfig(level=logging.DEBUG)  # 打印源码中的日志
    driver = webdriver.Chrome()
    driver.get('https://www.baidu.com')

    打印日志如下:

    DEBUG:selenium.webdriver.remote.remote_connection:POST http://localhost:63959/session {"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName": "chrome", "pageLoadStrategy": "normal", "goog:chromeOptions": {"extensions": [], "args": []}}}}
    DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): localhost:63959
    DEBUG:urllib3.connectionpool:http://localhost:63959 "POST /session HTTP/1.1" 200 794
    DEBUG:selenium.webdriver.remote.remote_connection:Remote response: status=200 | data={"value":{"capabilities":{"acceptInsecureCerts":false,"browserName":"chrome","browserVersion":"102.0.5005.115","chrome":{"chromedriverVersion":"102.0.5005.61 (0e59bcc00cc4985ce39ad31c150065f159d95ad3-refs/branch-heads/5005@{#819})","userDataDir":"C:\\Users\\jeff.xie\\AppData\\Local\\Temp\\scoped_dir15248_1149020991"},"goog:chromeOptions":{"debuggerAddress":"localhost:63963"},"networkConnectionEnabled":false,"pageLoadStrategy":"normal","platformName":"windows","proxy":{},"setWindowRect":true,"strictFileInteractability":false,"timeouts":{"implicit":0,"pageLoad":300000,"script":30000},"unhandledPromptBehavior":"dismiss and notify","webauthn:extension:credBlob":true,"webauthn:extension:largeBlob":true,"webauthn:virtualAuthenticators":true},"sessionId":"a402557c61699397cccbdabf77e06cd1"}} | headers=HTTPHeaderDict({'Content-Length': '794', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
    DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
    DEBUG:selenium.webdriver.remote.remote_connection:POST http://localhost:63959/session/a402557c61699397cccbdabf77e06cd1/url {"url": "https://www.baidu.com"}
    DEBUG:urllib3.connectionpool:http://localhost:63959 "POST /session/a402557c61699397cccbdabf77e06cd1/url HTTP/1.1" 200 14
    DEBUG:selenium.webdriver.remote.remote_connection:Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
    DEBUG:selenium.webdriver.remote.remote_connection:Finished Request

    可以看到,首先通过 Webdriver 启动浏览器驱动程序 chromedriver.exe,打开浏览器,并获得 sessionId,然后再向带上 sessionId 向浏览器发送打开百度主页的请求。

    下面自己通过 requests 模块来模拟这一系列过程(执行之前首先要打开selenium-server 服务,我是使用的 selenium-server 服务,你也可以使用浏览器服务)
     

    首先在cmd中启动selenium-server  服务

     然后再Pycharm中运行以下代码

    # coding=utf-8
    import requests
    
    
    class MySelenium:
        def __init__(self):
            self.driver = self.my_webdriver_chrome()
    
        def my_webdriver_chrome(self):
            '''
            获取driver
            :return:
            '''
            driver_url = 'http://127.0.0.1:4444/wd/hub/session/'
            # 打开浏览器的请求参数
            driver_value = {"capabilities":
                                {"alwaysMatch":
                                     {"browserName": "chrome", }
                                 }
                            }
    
            # 发送求清
            response_session = requests.post(driver_url, json=driver_value)
            # 获取返回的 sessionId
            print(response_session.json())
            # 获取session ID
            my_sessionId = response_session.json()['value']['sessionId']
    
            return driver_url + my_sessionId
    
        def my_get(self, url):
            '''
            通过get方式访问网址
            :param url:
            :return:
            '''
            temp_url = self.driver + '/url'
            value = {'url': url}
            requests.post(temp_url, json=value)
    
    
    if __name__ == '__main__':
        obj_my_selenium = MySelenium()
        obj_my_selenium.my_get('https://www.baidu.com/')
    

     

    在cmd中的log

    10:43:36.123 INFO [ActiveSessionFactory.apply] - Capabilities are: {
      "browserName": "chrome"
    }
    10:43:36.124 INFO [ActiveSessionFactory.lambda$apply$11] - Matched factory org.openqa.selenium.grid.session.remote.ServicedSession$Factory (provider: org.openqa.selenium.chrome.ChromeDriverService)
    Starting ChromeDriver 102.0.5005.61 (0e59bcc00cc4985ce39ad31c150065f159d95ad3-refs/branch-heads/5005@{#819}) on port 28904
    Only local connections are allowed.
    Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
    ChromeDriver was started successfully.
    10:43:38.565 INFO [ProtocolHandshake.createSession] - Detected dialect: W3C
    10:43:38.594 INFO [RemoteSession$Factory.lambda$performHandshake$0] - Started new session f40b23a4faffac1dadf030c5073f5b7a (org.openqa.selenium.chrome.ChromeDriverService)
     

    代码返回的session ID

    # 获取返回的 sessionId

    print(response_session.json())

    {'value': {'sessionId': '287f14c5789390e0570ae8c5ae62dc9f', 'capabilities': {'acceptInsecureCerts': False, 'browserName': 'chrome', 'browserVersion': '102.0.5005.115', 'chrome': {'chromedriverVersion': '102.0.5005.61 (0e59bcc00cc4985ce39ad31c150065f159d95ad3-refs/branch-heads/5005@{#819})', 'userDataDir': 'C:\\Users\\jeff.xie\\AppData\\Local\\Temp\\scoped_dir28400_1955656845'}, 'goog:chromeOptions': {'debuggerAddress': 'localhost:49896'}, 'networkConnectionEnabled': False, 'pageLoadStrategy': 'normal', 'platformName': 'windows', 'proxy': {}, 'setWindowRect': True, 'strictFileInteractability': False, 'timeouts': {'implicit': 0, 'pageLoad': 300000, 'script': 30000}, 'unhandledPromptBehavior': 'dismiss and notify', 'webauthn:extension:credBlob': True, 'webauthn:extension:largeBlob': True, 'webauthn:virtualAuthenticators': True, 'webdriver.remote.sessionid': '287f14c5789390e0570ae8c5ae62dc9f'}}}

    每一条 Selenium 脚本,

    一个 http 请求会被创建并且发送给浏览器,

    浏览器执行具体的测试步骤后再将步骤执行结果返回给 Remote Server,

    Remote Server 又将结果返回给 Selenium 的脚本,

    如果是错误的 http 代码我们就会在控制台看到对应的报错信息。
     

    from selenium import webdriver
    import logging
    from selenium.webdriver.common.by import By
    
    logging.basicConfig(level=logging.DEBUG)
    driver = webdriver.Chrome()
    driver.get('https://www.baidu.com')
    logging.info("Start to test!!!!!!!!!!!!!")
    driver.find_element(By.ID,"kw").send_keys("python")
    logging.info("Start to click!!!!!!!!!!!!!")
    driver.find_element(By.ID,"su").click()
    print("OKOKOKO")

    我们可以通过log来分析上面的代码具体有什么操作

    查找元素并sendkeys执行log

    INFO:root:Start to test!!!!!!!!!!!!!

    #携带参数发送请求
    DEBUG:selenium.webdriver.remote.remote_connection:POST http://localhost:51369/session/adb3143b146fe78c0ee16cdbded4d459/element {"using": "css selector", "value": "[id=\"kw\"]"}

    #返回状态码

    DEBUG:urllib3.connectionpool:http://localhost:51369 "POST /session/adb3143b146fe78c0ee16cdbded4d459/element HTTP/1.1" 200 88

    #响应数据

    DEBUG:selenium.webdriver.remote.remote_connection:Remote response: status=200 | data={"value":{"element-6066-11e4-a52e-4f735466cecf":"68c631e2-3c2f-4d21-84cd-09939da46e28"}} | headers=HTTPHeaderDict({'Content-Length': '88', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})

    #查找元素完成
    DEBUG:selenium.webdriver.remote.remote_connection:Finished Request

    #发起sendkey请求,携带查找元素时的返回数据
    DEBUG:selenium.webdriver.remote.remote_connection:POST http://localhost:51369/session/adb3143b146fe78c0ee16cdbded4d459/element/68c631e2-3c2f-4d21-84cd-09939da46e28/value {"text": "python", "value": ["p", "y", "t", "h", "o", "n"], "id": "68c631e2-3c2f-4d21-84cd-09939da46e28"}
    DEBUG:urllib3.connectionpool:http://localhost:51369 "POST /session/adb3143b146fe78c0ee16cdbded4d459/element/68c631e2-3c2f-4d21-84cd-09939da46e28/value HTTP/1.1" 200 14

    #执行sendkey动作
    DEBUG:selenium.webdriver.remote.remote_connection:Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})

    #执行完成
    DEBUG:selenium.webdriver.remote.remote_connection:Finished Request

    查找元素并click执行log

    INFO:root:Start to click!!!!!!!!!!!!!

    DEBUG:selenium.webdriver.remote.remote_connection:POST http://localhost:51369/session/adb3143b146fe78c0ee16cdbded4d459/element {"using": "css selector", "value": "[id=\"su\"]"}
    DEBUG:urllib3.connectionpool:http://localhost:51369 "POST /session/adb3143b146fe78c0ee16cdbded4d459/element HTTP/1.1" 200 88
    DEBUG:selenium.webdriver.remote.remote_connection:Remote response: status=200 | data={"value":{"element-6066-11e4-a52e-4f735466cecf":"52336fcb-f3c8-4c74-a545-2a30ebe94034"}} | headers=HTTPHeaderDict({'Content-Length': '88', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
    DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
    DEBUG:selenium.webdriver.remote.remote_connection:POST http://localhost:51369/session/adb3143b146fe78c0ee16cdbded4d459/element/52336fcb-f3c8-4c74-a545-2a30ebe94034/click {"id": "52336fcb-f3c8-4c74-a545-2a30ebe94034"}
    DEBUG:urllib3.connectionpool:http://localhost:51369 "POST /session/adb3143b146fe78c0ee16cdbded4d459/element/52336fcb-f3c8-4c74-a545-2a30ebe94034/click HTTP/1.1" 200 14
    DEBUG:selenium.webdriver.remote.remote_connection:Remote response: status=200 | data={"value":null} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'})
    DEBUG:selenium.webdriver.remote.remote_connection:Finished Request

    OKOKOKO

  • 相关阅读:
    【1. 操作系统—概述】
    html父级标签和子标签的点击事件重叠问题
    学习记录2022
    优雅草蜻蜓z系统暗影版前台崩溃,后台提示:系统接口异常502,java项目管理yyc-admin后台管理系统服务无法启动的解决方案
    智慧安防:监控防盗两不误的安防视频监控系统是什么样的?
    怎样将word默认Microsoft Office,而不是WPS
    字符串_哈希
    李宏毅机器学习第一课(结尾附作业模型详细分析)
    区,段,碎片区与表空间结构
    八零后程序员,北漂十年最终回乡:“所有的漂泊,注定无法落脚”
  • 原文地址:https://blog.csdn.net/qq_30273575/article/details/127859412