欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Webdriver基本原理解析之FirefoxDriver

程序员文章站 2022-05-02 16:02:21
...

最近仔细看了下Selenium WebDriver的源码, 发现WebDriver的工作原理,理解起来其实还是挺简单的.以下分步介绍:

 

首先,在理解webdriver的前提是了解webdriver的协议.

关于协议可以参考: https://www.w3.org/TR/webdriver/#go. Firefox官方通过插件的形式实现了这个协议,插件的文件名是webdriver.xpi, 它存放在selenium-firefox-driver.jar的org.openqa.selenium.firefox包下面.

 

其次, Firefox浏览器被启动后, 同时也加载了webdriver.xpi这个插件,启动了一个实现webdriver协议的http server.

当我们以如下的代码形式启动Firefoxdriver的时候:

WebDriver driver = new FirefoxDriver();

 

表面上,我们看到的是Firefox浏览器被启动了, 但是本质被打开的浏览器成了一个http server.这个server的默认端口是7055, 此后它开始响应client端(我们的Java代码)的各种对浏览器操作行为的请求. 这个过程的主要逻辑在FirefoxDriver的父类RemoteWebDriver:

public RemoteWebDriver(CommandExecutor executor, Capabilities desiredCapabilities,
      Capabilities requiredCapabilities) {
    this.executor = executor;

    init(desiredCapabilities, requiredCapabilities);

    if (executor instanceof NeedsLocalLogs) {
      ((NeedsLocalLogs)executor).setLocalLogs(localLogs);
    }

    try {
      startClient();       //启动浏览器
    } catch (RuntimeException e) {
      try {
        stopClient();
      } catch (Exception ignored) {
        // Ignore the clean-up exception. We'll propagate the original failure.
      }

      throw e;
    }

    try {
      startSession(desiredCapabilities, requiredCapabilities);
    } catch (RuntimeException e) {
      try {
        quit();
      } catch (Exception ignored) {
        // Ignore the clean-up exception. We'll propagate the original failure.
      }

      throw e;
    }
  }

 

启动浏览器的逻辑在startClient()方法. RemoteWebDriver.startClient()方法是空的. 它的具体实现在它的子类中. 由于每个浏览器启动的方式显然是会有区别的,所以这个也就很好理解了

 

最后, 在浏览器和Webdiver的http server被启动之后, 我们就可以使用webdriver实例的api去操作浏览器了.

接下去我们每次对浏览器的一次操作,本质上都是向http server发送一个restful的http请求. 它的核心逻辑在org.openqa.selenium.remote.HttpCommandExecutor.execute(Command)方法中, 所有的用户操作与请求的URL对应关系在org.openqa.selenium.remote.http.JsonHttpCommandCodec.JsonHttpCommandCodec():

public JsonHttpCommandCodec() {
    defineCommand(STATUS, get("/status"));
    defineCommand(GET, post("/session/:sessionId/url"));
    defineCommand(GET_ALL_SESSIONS, get("/sessions"));
    defineCommand(NEW_SESSION, post("/session"));
    defineCommand(GET_CAPABILITIES, get("/session/:sessionId"));
    defineCommand(QUIT, delete("/session/:sessionId"));

    defineCommand(GET_SESSION_LOGS, post("/logs"));
    defineCommand(GET_LOG, post("/session/:sessionId/log"));
    defineCommand(GET_AVAILABLE_LOG_TYPES, get("/session/:sessionId/log/types"));

    defineCommand(SWITCH_TO_FRAME, post("/session/:sessionId/frame"));
    defineCommand(SWITCH_TO_PARENT_FRAME, post("/session/:sessionId/frame/parent"));
    defineCommand(CLOSE, delete("/session/:sessionId/window"));
}

 

比如说, 我们要执行driver.get("http://www.baidu.com")这行代码的时候, 对应的http请求是上面定义的defineCommand(GET, post("/session/:sessionId/url")), sessionId是用来被具体ID替换的.

 

实际上程序中HttpRequest得到的URL是: /session/930ce0fc-bcde-48bd-8f25-0bd2b2af716d/url

HttpRequest的content内容是: http://www.baidu.com

最终它们通过httpClient调用来执行:

 

HttpResponse httpResponse = client.execute(httpRequest, true);

 

以上就是FirefoxDriver的基本运行原理

 

转载请注明出处: http://lijingshou.iteye.com/blog/2304334

相关标签: webdriver selenium2