selenium源码分析-webdriver(二)
最近比较空闲就仔细看了一下Selenium的源码,因为主要是使用WebDriver所以重点关注了一下WebDriver的工作原理。在前一篇blog里已经解释过了WebDriver与之前Selenium的JS注入实现不同,直接利用了浏览器native support来操作浏览器。所以对于不同平台,不同的浏览器,必须依赖一个特定的浏览器的native component来实现把WebDriver API的调用转化为浏览器的native invoke。
在我们new一个WebDriver的过程中,Selenium首先会确认浏览器的native component是否存在可用而且版本匹配。接着就在目标浏览器里启动一整套Web Service,这套Web Service使用了Selenium自己设计定义的协议,名字叫做The WebDriver Wire Protocol。这套协议非常之强大,几乎可以操作浏览器做任何事情,包括打开、关闭、最大化、最小化、元素定位、元素点击、上传文件等等等等。
WebDriver Wire协议是通用的,也就是说不管是FirefoxDriver还是ChromeDriver,启动之后都会在某一个端口启动基于这套协议的Web Service。例如FirefoxDriver初始化成功之后,默认会从http://localhost:7055开始,而ChromeDriver则大概是http://localhost:46350之类的。接下来,我们调用WebDriver的任何API,都需要借助一个ComandExecutor发送一个命令,实际上是一个HTTP request给监听端口上的Web Service。在我们的HTTP request的body中,会以WebDriver Wire协议规定的JSON格式的字符串来告诉Selenium我们希望浏览器接下来做社么事情。
这里笔者初步画了一个图来表示各种WebDriver的工作原理:
从上图中我们可以看出,不同浏览器的WebDriver子类,都需要依赖特定的浏览器原生组件,例如Firefox就需要一个add-on名字叫webdriver.xpi。而IE的话就需要用到一个dll文件来转化Web Service的命令为浏览器native的调用。另外,图中还标明了WebDriver Wire协议是一套基于RESTful的web service。如果不明白什么是RESTful的,可以参见笔者之前另外一篇介绍REST的blog(http://blog.csdn.net/ant_yan/article/details/7963517)
关于WebDriver Wire协议的细节,比如希望了解这套Web Service能够做哪些事情,可以阅读Selenium官方的协议文档, 在Selenium的源码中,我们可以找到一个HttpCommandExecutor这个类,里面维护了一个Map<String, CommandInfo>,它负责将一个个代表命令的简单字符串key,转化为相应的URL,因为REST的理念是将所有的操作视作一个个状态,每一个状态对应一个URI。所以当我们以特定的URL发送HTTP request给这个RESTful web service之后,它就能解析出需要执行的操作。截取一段源码如下:
- nameToUrl = ImmutableMap.<String, CommandInfo>builder()
- .put(NEW_SESSION, post("/session"))
- .put(QUIT, delete("/session/:sessionId"))
- .put(GET_CURRENT_WINDOW_HANDLE, get("/session/:sessionId/window_handle"))
- .put(GET_WINDOW_HANDLES, get("/session/:sessionId/window_handles"))
- .put(GET, post("/session/:sessionId/url"))
- // The Alert API is still experimental and should not be used.
- .put(GET_ALERT, get("/session/:sessionId/alert"))
- .put(DISMISS_ALERT, post("/session/:sessionId/dismiss_alert"))
- .put(ACCEPT_ALERT, post("/session/:sessionId/accept_alert"))
- .put(GET_ALERT_TEXT, get("/session/:sessionId/alert_text"))
- .put(SET_ALERT_VALUE, post("/session/:sessionId/alert_text"))
可以看到实际发送的URL都是相对路径,后缀多以/session/:sessionId开头,这也意味着WebDriver每次启动浏览器都会分配一个独立的sessionId,多线程并行的时候彼此之间不会有冲突和干扰。例如我们最常用的一个WebDriver的API,getWebElement在这里就会转化为/session/:sessionId/element这个URL,然后在发出的HTTP request body内再附上具体的参数比如by ID还是CSS还是Xpath,各自的值又是什么。收到并执行了这个操作之后,也会回复一个HTTP response。内容也是JSON,会返回找到的WebElement的各种细节,比如text、CSS selector、tag name、class name等等。以下是解析我们说的HTTP response的代码片段:
- try {
- response = new JsonToBeanConverter().convert(Response.class, responseAsText);
- } catch (ClassCastException e) {
- if (responseAsText != null && "".equals(responseAsText)) {
- // The remote server has died, but has already set some headers.
- // Normally this occurs when the final window of the firefox driver
- // is closed on OS X. Return null, as the return value _should_ be
- // being ignored. This is not an elegant solution.
- return null;
- }
- throw new WebDriverException("Cannot convert text to response: " + responseAsText, e);
- } //...
相信总结道这里,应该对WebDriver的运行原理应该清楚了!其实挺佩服这一套RESTful web service的设计。感觉封装WebDriver暴露出来的public API还可以更加友好跟强大一点,这次就先总结道这里,会继续分析Selenium源码,继续分享的!
文章来源:http://blog.csdn.net/ant_ren/article/details/7970793
selenium源码分析-webdriver(二)的更多相关文章
- DataTable源码分析(二)
DataTable源码分析(二) ===================== DataTable函数分析 ---------------- DataTable作为整个插件的入口,完成了整个表格的数据初 ...
- 一个普通的 Zepto 源码分析(二) - ajax 模块
一个普通的 Zepto 源码分析(二) - ajax 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以 ...
- Zepto源码分析(二)奇淫技巧总结
Zepto源码分析(一)核心代码分析 Zepto源码分析(二)奇淫技巧总结 目录 * 前言 * 短路操作符 * 参数重载(参数个数重载) * 参数重载(参数类型重载) * CSS操作 * 获取属性值的 ...
- Koa源码分析(二) -- co的实现
Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: Koa源码分析(一) -- generator Koa源码分析(二) -- co的实现 Koa源码分 ...
- Unity时钟定时器插件——Vision Timer源码分析之二
Unity时钟定时器插件——Vision Timer源码分析之二 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 前面的已经介绍了vp_T ...
- Tomcat源码分析(二)------ 一次完整请求的里里外外
Tomcat源码分析(二)------ 一次完整请求的里里外外 前几天分析了一下Tomcat的架构和启动过程,今天开始研究它的运转机制.Tomcat最本质就是个能运行JSP/Servlet的Web ...
- spark 源码分析之二十一 -- Task的执行流程
引言 在上两篇文章 spark 源码分析之十九 -- DAG的生成和Stage的划分 和 spark 源码分析之二十 -- Stage的提交 中剖析了Spark的DAG的生成,Stage的划分以及St ...
- Django之DRF源码分析(二)---数据校验部分
Django之DRF源码分析(二)---数据校验部分 is_valid() 源码 def is_valid(self, raise_exception=False): assert not hasat ...
- Kubernetes Deployment 源码分析(二)
概述startDeploymentController 入口逻辑DeploymentController 对象DeploymentController 类型定义DeploymentController ...
随机推荐
- C# 拷贝目录
public class DirectoryExtends { /// <summary> /// 拷贝目录 /// </summary> /// <param name ...
- Redis3.0.7 cluster/集群 安装配置教程
1.前言 环境:CentOS-6.7-i386-LiveDVD 安装的CentOs系统 节点: 6个节点,3个主节点.3个从节点(由于redis默认需要3个主节点,如果想每个主节点有一个从节点,这是最 ...
- spring之BeanFactoryAware接口
springBeanFactoryAware (转)要直接在自己的代码中读取spring的bean,我们除了根据常用的set外,也可以通过spring的BeanFactoryAware接口实现,只要实 ...
- [js/jquery]移动端手势拖动,放大,缩小预览图片
摘要 有这样的需求需要在手机端预览图片的时候,实现图片的手势拖动,放大缩小功能.最终通过touch.js这个插件实现了效果. touch.js Touch.js是移动设备上的手势识别与事件库, 由百度 ...
- html css 网络 页面布局 颜色 参考 拾取器网址
http://blog.163.com/wujinhongisme@126/blog/static/3613698020095115919389/ ========================== ...
- 如何修改mysql默认的数据库密码
1,首先链接到数据库 mysql -h 127.0.0.1 -uroot -p 2,选择数据库 use mysql; 3,修改user表的密码 UPDATE user SET Password=PAS ...
- Stm32 debug停留在"BKPT 0xAB"或者"SWI 0xAB"的解决办法。
一..背景: 曾经在工作中接触过STM32一段时间,但没有深入的去学习,只是用前辈搭建好的模型来实现一些功能罢了,俗话说的好,大树底下好乘凉,开发确实轻松了,可是不深究点,又觉着心里不踏实,然而也一直 ...
- 网络编程2-UDP编程(DatagramSocket)
1.传输层有两个协议,一个是tcp协议,另一个是udp协议,tcp协议通过socket编程.udp通过数据报编程. UDP协议: (1)将数据.源地址.目的地址 封装成数据包,不需要建立链接 (2)每 ...
- VIM使用学习笔记 : 按键说明
VIM有三种模式: 一般模式 上下左右移动光标,删除字符或删除整行,复制粘贴 编辑模式 i I i O a A r R 进入编辑模式 命令模式 在一般模式种输入 : / ?,可 ...
- Dp~Hrbust1426( 集训队的晚餐 )
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAxsAAAPRCAYAAACVrbUbAAAgAElEQVR4nOzdW5Bcx33n+X7aiH3b2J