Selenium实现原理

news2025/7/11 1:23:00

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/8786.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[go学习笔记.第十五章.反射] 1.反射的基本介绍以及实践

一.反射的引入以及基本介绍 1.看两个问题 (1).对于结构体的序列化和反序列化,看一段代码 package mainimport("fmt" "encoding/josn" )type Monster struct {Name string json:"monsterName"Age int json:"monsterAge&quo…

deque容器(20221115)

1、基本概念 功能:双端数组,可以对头端进行插入删除元素 deque与vector的区别: vector对应头部的插入删除效率低,数据量越大,效率越低 deque对头部的插入删除速度比vector快 vector访问元素速度比deque快 deque内…

sanic 教程

sanic 教程 在Sanic的生命周期流程大致如下: http请求——Sanic解析request——匹配路由——请求中间件——视图函数——响应中间件——http响应 依赖库 sanic21.3.4 sanic-jwt1.7.0 sanic-openapi21.12.0 gunicorn20.1.0 PyMySQL1.0.2 aiomysql0.1.1 DBUtils1.3…

WPS(WSC)中M1 到M8 图解

背景 之前实习的时候就学了Wifi p2p相关的东西,当时找M1到M8的功能把我累惨了,找到的还全是千篇一律的东西,讲的不是很清楚(当然原版出书的那个前辈肯定是懂的),但是对我等小白不友好,就萌生了这…

3.线性代数-矩阵

矩阵和Tensor1. Tensor2.矩阵3.线性代数正确打开方式3.1 行视图3.2 列视图4.线性相关和线性无关5. Span、基和子空间(Subspace)6.四个基本的子空间6.1 列空间6.2 零空间6.3 行空间6.4 左零空间6.5 四个基本子空间的关系7.可逆矩阵8.方阵的特征值与特征向量9.特征分解9.1一般矩阵…

【Pytorch with fastai】第 7 章 :训练SOTA的模型

🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎 📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃 🎁欢迎各位→点赞…

Nginx优化方案

目录 一、Nginx返回错误页面 1、HTTP常见状态代码列表 二、Nginx状态页面 1、安装status模块 2、激活status 三、优化并发连接数 1、压力测试软件ab(http-tools) 2、优化并发连接数 2.1、修改nginx并发数 2.2、修改内核最大文件数量 四、Nginx…

吉莱斯皮随机模拟算法(SSA)(Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

【K8S系列】第十讲:Knative 简介

目录 一、 Serverless介绍 二、Knative 介绍 2.1 Knative 的定位 2.2 Knative的组成 2.2.1 Build 构建系统 2.2.2 Serving:服务系统 2.2.3 Eventing:事件系统 补充: 三、总结: 一、 Serverless介绍 在讲Knative之前&a…

【毕业设计】机器视觉手势检测和识别系统 - python 深度学习

文章目录0 前言1 实现效果2 技术原理2.1 手部检测2.1.1 基于肤色空间的手势检测方法2.1.2 基于运动的手势检测方法2.1.3 基于边缘的手势检测方法2.1.4 基于模板的手势检测方法2.1.5 基于机器学习的手势检测方法3 手部识别3.1 SSD网络3.2 数据集3.3 最终改进的网络结构4 最后0 前…

线程池源码解析 2.工作原理与内部结构

线程池源码解析—工作原理与内部结构 工作原理 概述 线程池是线程的池子,本质上是通过单个线程执行多个并发任务,使得尽量少的创建线程,减少开销。在线程池内部,是没有区分核心线程和非核心线程的,是通过 Set 集合的…

拒绝内卷,阿里架构师整理的这份Java核心手册,堪称最强

2022年注定是不寻常的一年,在今年因为疫情以及各大大厂纷纷传来裁员的消息,引得整个互联网圈动荡不堪。腾讯裁员30%、京东、百度、字节等大厂都在纷纷裁员,引的这些中厂和小厂也跟风裁员。 这个时候外部的各种变化愈发证明一个重要的一点&am…

2022.11.7-11.13 AI行业周刊(第123期):技术人员的职业发展在哪里?

篇章一:技术人员的职业发展 上周和大学时的舍友聊天,交流当前大家的生活状态。 我们已经本科毕业将近10年了,他目前也有两个孩子,在湖北的一个地级市中,从事的是通信行业。 不过随着工作的时间越久,他发…

软件测试面试真题 | 黑盒测试和白盒测试的基本概念是什么?

在软件测试的面试中,什么是黑盒测试,什么是白盒测试是特别容易被问到的一个问题。 面试官问出这个问题,其实考察的是大家对于软件测试基础理论的掌握程度。下面来梳理一下这个问题的回答思路。 黑盒测试 黑盒测试会把被测的软件看作是一个…

只会加班的项目经理,迟早被淘汰

早上好,我是老原。 最近看到一个文章的标题「废掉一个人最好的方式,就是让他忙到没时间学习」,具体内容是什么我还没有细读,只看完标题,有一丝心酸和自豪: 有那么一群人,在玻璃渣里找糖吃&…

皮带跑偏检测系统

皮带跑偏检测系统对皮带运行状态进行全天候实时监测,一旦皮带跑偏检测系统监测到现场皮带跑偏、撕裂、堆煤、异物等异常情况时,系统马上开展警报,通知后台,并提醒相关人员及时处置。皮带跑偏检测系统并把警报截屏和视频储存到数据…

附参考文献丨艾美捷Cholesterol胆固醇说明书

Cholesterol胆固醇以固体形式提供。可以通过将胆固醇溶解在所选择的溶剂中来制备储备溶液,该溶剂应使用惰性气体吹扫。胆固醇以约30mg/ml的浓度溶于有机溶剂氯-仿中。 艾美捷Cholesterol胆固醇参数: CAS号:57-88-5 正式名称:&am…

自动驾驶入门:预测

目录 概念 预测方式 障碍物预测 递归神经网络在预测中的应用 轨迹生成 概念 无人车是在许多物体间穿梭行驶,其中许多物体本身就是一直在移动的,比如像其他汽车、自行车、行人。无人车需要预测这些物体的行为,这样才能确保做出最佳决策。…

工作中对InheritableThreadLocal使用的思考

最近在工作中结合线程池使用 InheritableThreadLocal 出现了获取线程变量“错误”的问题,看了相关的文档和源码后在此记录。 1. 先说结论 InheritableThreadLocal 只有在父线程创建子线程时,在子线程中才能获取到父线程中的线程变量;当配合…

coding持续集成

先看看官网的一些操作提示 1、创建SSH密钥对 2、创建制品仓库 看完官网的介绍,持续集成需要提前准备好SSH凭证和制品仓库,下面将让我们动手开始吧 一、创建SSH密钥对 登录服务器控制台,创建 SSH 密钥对。获取私钥对后将其录入至 CODING 中…