Selenium实现原理
创始人
2024-01-22 12:15:43
0

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 requestsclass 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)# 获取返回的 sessionIdprint(response_session.json())# 获取session ID my_sessionId = response_session.json()['value']['sessionId']return driver_url + my_sessionIddef 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 Bylogging.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

相关内容

热门资讯

西陇科学002584投资者诉讼... (本文部分辑自“金融法律实务评论”微信公众号:touzifalv,涉及文章内容交流或咨询请关注公众号...
美劳动力数据遇冷,美联储政策转... 汇通财经APP讯——从10月挑战者裁员数据到昨天发布的私人ADP数据,美国近期数据持续暴击美国劳动力...
法务裸辞后、做律师前,我去寺庙... 01 去寺庙做义工的契机 2023年从某零售行业top公司法务工作裸辞后,身心都非常困顿和迷茫,既不...
原创 特... “我们不再向乌克兰付钱,现在他们通过北约向我们付钱。” 当地时间2025年11月11日,特朗普在白宫...
因买卖合同纠纷,儋州金大不锈钢... 天眼查APP显示,近日,儋州金大不锈钢加工有限公司新增一则开庭公告,案由为“买卖合同纠纷”,原告为儋...
法律为什么严禁律师承诺结果?既... “这官司能不能100%赢?” “我要你给个准话,保证一定把他送进去” “不保证结果凭什么收钱?” “...
美国法官推迟批准Epic与谷歌... IT之家 11 月 12 日消息,据游戏媒体 VGC 今天报道,加州一名法官已推迟批准 Epic 与...
女子照片被恶意P图发至300人... 封面新闻记者 杨澜 张海琳 近日,安徽合肥的程女士在社交媒体上发布的自拍照片,被一名男摄影师恶意P图...
因劳动争议,缪雩鸿起诉建元信托 天眼查APP显示,近日,缪雩鸿新增一则开庭公告,案由为“劳动争议”,原告为缪雩鸿,被告为建元信托股份...
格力电器:已发布《市值管理制度... 证券之星消息,格力电器(000651)11月11日在投资者关系平台上答复投资者关心的问题。 投资者提...