zoukankan      html  css  js  c++  java
  • 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之后,它就能解析出需要执行的操作。截取一段源码如下:

    [java] view plaincopy
     
     
    1. nameToUrl = ImmutableMap.<String, CommandInfo>builder()  
    2.         .put(NEW_SESSION, post("/session"))  
    3.         .put(QUIT, delete("/session/:sessionId"))  
    4.         .put(GET_CURRENT_WINDOW_HANDLE, get("/session/:sessionId/window_handle"))  
    5.         .put(GET_WINDOW_HANDLES, get("/session/:sessionId/window_handles"))  
    6.         .put(GET, post("/session/:sessionId/url"))  
    7.   
    8.             // The Alert API is still experimental and should not be used.  
    9.         .put(GET_ALERT, get("/session/:sessionId/alert"))  
    10.         .put(DISMISS_ALERT, post("/session/:sessionId/dismiss_alert"))  
    11.         .put(ACCEPT_ALERT, post("/session/:sessionId/accept_alert"))  
    12.         .put(GET_ALERT_TEXT, get("/session/:sessionId/alert_text"))  
    13.         .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的代码片段:

    [java] view plaincopy
     
     
    1. try {  
    2.         response = new JsonToBeanConverter().convert(Response.class, responseAsText);  
    3.       } catch (ClassCastException e) {  
    4.         if (responseAsText != null && "".equals(responseAsText)) {  
    5.           // The remote server has died, but has already set some headers.  
    6.           // Normally this occurs when the final window of the firefox driver  
    7.           // is closed on OS X. Return null, as the return value _should_ be  
    8.           // being ignored. This is not an elegant solution.  
    9.           return null;  
    10.         }  
    11.         throw new WebDriverException("Cannot convert text to response: " + responseAsText, e);  
    12.       } //...  


    相信总结道这里,应该对WebDriver的运行原理应该清楚了!其实挺佩服这一套RESTful web service的设计。感觉封装WebDriver暴露出来的public API还可以更加友好跟强大一点,这次就先总结道这里,会继续分析Selenium源码,继续分享的!

    文章来源:http://blog.csdn.net/ant_ren/article/details/7970793

  • 相关阅读:
    bzoj3505 数三角形 组合计数
    cogs2057 殉国 扩展欧几里得
    cogs333 荒岛野人 扩展欧几里得
    bzoj1123 BLO tarjan求点双连通分量
    poj3352 road construction tarjan求双连通分量
    cogs1804 联合权值 dp
    cogs2478 简单的最近公共祖先 树形dp
    cogs1493 递推关系 矩阵
    cogs2557 天天爱跑步 LCA
    hdu4738 Caocao's Bridge Tarjan求割边
  • 原文地址:https://www.cnblogs.com/testlife007/p/4654510.html
Copyright © 2011-2022 走看看