最近比较空闲就仔细看了一下Selenium的源码,由于主要是使用WebDriver因此重点关注了一下WebDriver的工做原理。在前一篇blog里已经解释过了WebDriver与以前Selenium的JS注入实现不一样,直接利用了浏览器native support来操做浏览器。因此对于不一样平台,不一样的浏览器,必须依赖一个特定的浏览器的native component来实现把WebDriver API的调用转化为浏览器的native invoke。java
在咱们new一个WebDriver的过程当中,Selenium首先会确认浏览器的native component是否存在可用并且版本匹配。接着就在目标浏览器里启动一整套Web Service,这套Web Service使用了Selenium本身设计定义的协议,名字叫作The WebDriver Wire Protocol。这套协议很是之强大,几乎能够操做浏览器作任何事情,包括打开、关闭、最大化、最小化、元素定位、元素点击、上传文件等等等等。web
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的工做原理:session
从上图中咱们能够看出,不一样浏览器的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以后,它就能解析出须要执行的操做。截取一段源码以下:post
能够看到实际发送的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的代码片断:ui
相信总结道这里,应该对WebDriver的运行原理应该清楚了!其实挺佩服这一套RESTful web service的设计。感受封装WebDriver暴露出来的public API还能够更加友好跟强大一点,此次就先总结道这里,会继续分析Selenium源码,继续分享的!this
文章来源:http://blog.csdn.net/ant_ren/article/details/7970793google