WebDriver是W3C的一个标准,由Selenium主持。

具体的协议标准可以从http://code.google.com/p/selenium/wiki/JsonWireProtocol#Command_Reference   查看。

从这个协议中我们可以看到,WebDriver之所以能够实现与浏览器进行交互,是因为浏览器实现了这些协议。这个协议是使用JOSN通过HTTP进行传输。

它的实现使用了经典的Client-Server模式。客户端发送一个requset,服务器端返回一个response。

我们明确几个概念。

Client

调用 WebDriverAPI的机器。

Server

运行浏览器的机器。Firefox浏览器直接实现了WebDriver的通讯协议,而Chrome和IE则是通过ChromeDriver和InternetExplorerDriver实现的。

Session

服务器端需要维护浏览器的Session,从客户端发过来的请求头中包含了Session信息,服务器端将会执行对应的浏览器页面。

WebElement

这是WebDriverAPI中的对象,代表页面上的一个DOM元素。

举个实际的例子,下面代码的作用是”命令”firefox转跳到google主页:

WebDriver driver = new FirefoxDriver();
        //实例化一个Driver
 
        driver.get("http://www.google.com");

在执行driver.get("http://www.google.com")这句代码时,client,也就是我们的测试代码向remote server发送了如下的请求:

POSTsession/285b12e4-2b8a-4fe6-90e1-c35cba245956/url  post_data{"url":"http://google.com"}

通过post的方式请求localhost:port/hub/session/session_id/url地址,请求浏览器完成跳转url的操作。

如果上述请求是可接受的,或者说remote server是实现了这个接口,那么remote server会跳转到该post data包含的url,并返回如下的response

{"name":"get","sessionId":"285b12e4-2b8a-4fe6-90e1-c35cba245956","status":0,"value":""}

该response中包含如下信息

name:remote server端的实现的方法的名称,这里是get,表示跳转到指定url;

sessionId:当前session的id;

status:请求执行的状态码,非0表示未正确执行,这里是0,表示一切ok不许担心;

value:请求的返回值,这里返回值为空,如果client调用title接口,则该值应该是当前页面的title;

如果client发送的请求是定位某个特定的页面元素,则response的返回值可能是这样的:

{"name":"findElement","sessionId":"285b12e4-2b8a-4fe6-90e1-c35cba245956","status":0,"value":{"ELEMENT":"{2192893e-f260-44c4-bdf6-7aad3c919739}"}}

name,sessionId,status跟上面的例子是差不多的,区别是该请求的返回值是ELEMENT:{2192893e-f260-44c4-bdf6-7aad3c919739},表示定位到元素的id,通过该id,client可以发送如click之类的请求与 server端进行交互。

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给46350端口上的Web Service。在我们的HTTP request的body中,会以WebDriver Wire协议规定的JSON格式的字符串来告诉Selenium我们希望浏览器接下来做什么事情。

不同浏览器的WebDriver子类,都需要依赖特定的浏览器原生组件,例如Firefox就需要一个add-on名字叫webdriver.xpi。而IE的话就需要用到一个dll文件来转化Web Service的命令为浏览器native的调用。

关于WebDriver Wire协议的细节,比如希望了解这套Web Service能够做哪些事情,可以阅读Selenium官方的协议文档, 在Selenium的源码中,我们可以找到一个HttpCommandExecutor这个类,里面维护了一个Map, 它负责将一个个代表命令的简单字符串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等等。

WebDriver 工作原理的更多相关文章

  1. [转载]WebDriver工作原理

    转载自:https://www.cnblogs.com/testermark/p/3546287.html WebDriver的工作原理:  在我们new一个WebDriver的过程中,Seleniu ...

  2. WebDriver工作原理

    http://www.cnblogs.com/timsheng/archive/2012/06/12/2546957.html 通过研究selenium-webdriver的源码,笔者发现其实webd ...

  3. Selenium WebDriver 工作原理

    WebDriver与之前Selenium的js注入实现不同:Selenium通过JS来定位元素处理元素(基本上所有元素都可以定位到)WebDriver通过WebDriver API定位处理元素:通过浏 ...

  4. Selenium webdriver工作原理

    webdriver是以server-client 经典模式设计的 server端可以是任何浏览器作为remote server,职责就是处理client的请求并作出相应操作,response的具体内容 ...

  5. Selenium----Selenium WebDriver /RC工作原理

    1.Selenium RC 工作原理 说明:客户端库文件将命令传递给server.接着server使用selenium-core的javaScript命令传递给浏览器,浏览器会使用自带的javaScr ...

  6. webdriver的工作原理

    selenium1的原理就是使用js来驱动浏览器,因为现在基本不用,所以不做过多讨论,下面是我整理的webdriver的工作原理,大致就是通过命令请求webdriver,然后webdriver通过浏览 ...

  7. Selenium WebDriver的实现及工作原理

    笔者最近研究学习了selenium的实现和工作原理,阅读了selenium3.141.59的Java源码,没有读完哈...重点从两个接口(org.openqa.selenium.WebDriver和o ...

  8. Selenium WebDriver的工作原理

    先通过一个简单的类比说个好理解的,这个比喻是我从美版知乎Quora上看到的,觉得比较形象.好理解拿来用用. 我们可以把WebDriver驱动浏览器类比成出租车司机开出租车. 在开出租车时有三个角色: ...

  9. 【关于selenium自动化中,Webdriver的原理以及工作流程】

    原文地址:https://www.cnblogs.com/imyalost/p/7242747.html#4109245 作者:老 张 1.关于Webdriver 设计模式:按照Server-Clie ...

随机推荐

  1. #400 – 使用ItemsPanel 属性将WrapPanel 作为ListBox的显示面板(Using a WrapPanel as the Items Panel for a ListBox)

    原文:#400 – 使用ItemsPanel 属性将WrapPanel 作为ListBox的显示面板(Using a WrapPanel as the Items Panel for a ListBo ...

  2. Windows10放开Administrator权限

    手机上大家都喜欢使ROOT权限,root是超线用户的意思,但是Win10最高权限是Administrator管理员权限,但是系统默认是没有开启这个权限的需要系统安装好以后再次去开启. 方法/步骤 在桌 ...

  3. Dataguard学习笔记

    主库和备库之间的redo log传递,可以通过如下方式实现: 在主库端: log_archive_dest_1='主库本地路径' log_archive_dest_2='备库的net service名 ...

  4. mfc 创建一个C++ 类

     类创建向导  添加一个C++类  #pragma once的作用  认识类视图 一.类创建向导 二.添加一个C++类 认识类创建向导: 创新一个处理文字信息的类CMessage CMessa ...

  5. JetBrains全家桶使用攻略

    JetBrains全家桶使用攻略 今天狠狠心某宝买了一个key,可以使用15款开发软件,在此进行记录. 全家桶链接:https://www.jetbrains.com/products.html?fr ...

  6. 使用MUART0-P-1-2设置无线PM2.5感测环境

    信息搜集–> 处理分析–> 动作执行,这是IoT环境中最基本的组成要素,传感器搜集环境信息后,透过指定的通讯协议传送到至控制中枢,经过处理分析后再将命令送交各device端执行.要实现这样 ...

  7. JAVA枚举操作(获取值,转map集合)

    JAVA枚举相对来说比.NET的枚举功能强大,感觉就像是一种简化版的类对象,可以有构造方法,可以重载,可以继承接口等等,但不能继承类,JAVA枚举在实际开发中应用相当频繁,以下几个封装方法在实际开发中 ...

  8. Python模块搜索路径

    当一个名为 spam 的模块被导入的时候,解释器首先寻找具有该名称的内置模块.如果没有找到,然后解释器从 sys.path 变量给出的目录列表里寻找名为 spam.py 的文件.sys.path 初始 ...

  9. gitlab+jenkins持续集成--http方式连接gitlab

    http://v.youku.com/v_show/id_XMjk3NTYyMDUxMg==.html?spm=a2h3j.8428770.3416059.1

  10. Annotation 使用备忘2

    title: Annotation 使用备忘 date: 2018-01-02 20:48:43 tags: [Annotation] categories: [Programming,Java] - ...