Macaca [转] selenium webdriver 的工作原理

老马 · 2016年11月30日 · 最后由 UshioYu 回复于 2021年05月06日 · 5453 次阅读

通过调试一些小的 Appium 官方样例,或其他博客中的样例程序,发现 Appium 大部分底层用了 selenium webdriver 进行封装,目前发现的有 WebDriver(来自 selenium-api-2.52.0.jar 的 org.openqa.selenium.WebDriver)和 AndroidDriver(来自 java-client-3.4.0.jar 的 io.appium.java_client.android.AndroidDriver)他们都可以实现对官方样例安卓程序 ContactManager.apk 的自动化回放测试。

下边我们来看下 webdriver 的工作原理。

大致就是通过命令请求 webdriver,然后 webdriver 通过浏览器的 api 去做操作,并返回响应结果。用的协议是 json wire protocol,下面简单画了个流程图,不一定准确,只是个人理解。

详细的可以参考官方 W3C 介绍:https://www.w3.org/TR/2016/WD-webdriver-20160120/

webdriver 和浏览器的信息交互:

1 需要 chromedriver,之前安装过 npm 版本的 Appium 所以到本地硬盘 D: 搜索 chromedriver 发现在位置

D:\nodejs\node-global\node_modules\appium\node_modules\appium-chromedriver\chromedriver\win 的目录 2016/02/29 09:36

. 2016/02/29 09:36 .. 2016/02/29 09:36 5,285,376 chromedriver.exe 1 个文件 5,285,376 字节 2 个目录 102,209,937,408 可用字节

2 然后我们在该目录下执行

D:\nodejs\node-global\node_modules\appium\node_modules\appium-chromedriver\chromedriver\win>java -Dwebdriver.chrome.driver="chromedriver.exe" -jar D:\Install\Appium\selenium-server-standalone-2.52.0.jar 
11:42:46.756 INFO - Launching a standalone Selenium Server 
11:42:46.999 INFO - Java: Oracle Corporation 25.60-b23 
11:42:47.000 INFO - OS: Windows 10 10.0 amd64 
11:42:47.014 INFO - v2.52.0, with Core v2.52.0. Built from revision 4c2593c 
11:42:47.072 INFO - Driver class not found: com.opera.core.systems.OperaDriver 
11:42:47.074 INFO - Driver provider com.opera.core.systems.OperaDriver is not registered 
11:42:47.085 INFO - Driver provider org.openqa.selenium.safari.SafariDriver registration is skipped: registration capabilities Capabilities [{browserName=safari, version=, platform=MAC}] does not match the current platform WIN10 
11:42:47.399 INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub 
11:42:47.401 INFO - Selenium Server is up and running

3 编辑一段小的测试代码

package com_appium.my_app;

import java.net.URL;

import org.openqa.selenium.By;
import org.openqa.selenium.Platform;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.junit.Test;

public class TestWebdriverChrome {
 static WebDriver dr;

 @Test
 public  void testChrome() {
        DesiredCapabilities aDesiredcap = DesiredCapabilities.chrome();  
        //aDesiredcap.setBrowserName("chrome");
        aDesiredcap.setPlatform(Platform.WINDOWS);

        try {
            dr = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), aDesiredcap);
            dr.get("http://www.baidu.com");
            dr.findElement(By.id("kw")).sendKeys("webdriver");
            Thread.sleep(3000);
            dr.quit();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }
}

通过 Junit 执行后,将打开谷歌浏览器,自动打开百度 搜索 webdriver。日志输出如下:

11:43:06.897 INFO - Executing: [new session: Capabilities [{browserName=chrome, version=, platform=WINDOWS}]]) 
11:43:06.909 INFO - Creating a new session for Capabilities [{browserName=chrome, version=, platform=WINDOWS}] Starting ChromeDriver 2.21.371459 (36d3d07f660ff2bc1bf28a75d1cdabed0983e7c4) on port 33920 Only local connections are allowed. 11:43:09.301 INFO - Done: [new session: Capabilities [{browserName=chrome, version=, platform=WINDOWS}]] 
11:43:09.325 INFO - Executing: [get: http://www.baidu.com]) 
11:43:10.944 INFO - Done: [get: http://www.baidu.com] 1
1:43:10.984 INFO - Executing: [find element: By.id: kw]) 
11:43:11.028 INFO - Done: [find element: By.id: kw] 
11:43:11.057 INFO - Executing: [send keys: 0 [[ChromeDriver: chrome on XP (bd7bf32a4c4977e883ebb9920d63ebe4)] -> id: kw], [webdriver]])
11:43:11.396 INFO - Done: [send keys: 0 [[ChromeDriver: chrome on XP (bd7bf32a4c4977e883ebb9920d63ebe4)] -> id: kw], [webdriver]] 
11:43:14.406 INFO - Executing: [delete session: 7848fa1d-edd7-4b04-b16e-cd07188b718b]) 
11:43:15.932 INFO - Done: [delete session: 7848fa1d-edd7-4b04-b16e-cd07188b718b]

由此可见,代码的一个请求命令,webdriver 都会封装一个 executing,发送过去,发送成功后,再返回一个 done 表示处理成功。如果发生了异常,如找不到页面元素,则会在执行时抛异常

如果上面的看着还不够透彻,下面我们直接用 webdriver 的协议提供给我们的接口去操作。

您需要 HttpRequester 这款火狐插件来构造模拟 http 请求 https://addons.mozilla.org/En-us/firefox/addon/httprequester/

1.首先在浏览器输入http://localhost:4444/wd/hub

通过以下方式拿到 sessionid:fc6f9497-330f-4d6c-abe0-bd0587e57101

2.拿到 session 后,就可以请求拉

首先我们用接口访问个百度,接口地址:http://localhost:4444/wd/hub/session/5c81a944-55c6-4c2a-9e01-689bc43d335d/urljson 内容:{"url":,请求 "http://www.baidu.com/"}。

post 后见下图

3.查找百度搜索的输入框

使用接口/session/{session id}/element,post 请求,json 内容:{ "using": "id", "value": "kw" }

4.查找到后,我们要往输入框输入内容

调用接口:/session/{session id}/element/{element id}/value,post 请求,json 内容:{ "value": [ "qiaoyeye" ] }

注意:element id 是第三步中的响应结果 json 中的{"ELEMENT":"0"}0 值

以上三步的请求和 json 内容
http://localhost:4444/wd/hub/session/6d67fc28-fdce-48fc-b895-0de598287f7c/url
{"url": "http://www.baidu.com/"}

http://localhost:4444/wd/hub/session/6d67fc28-fdce-48fc-b895-0de598287f7c/element
{
"using": "id",
"value": "kw"
}

http://localhost:4444/wd/hub/session/6d67fc28-fdce-48fc-b895-0de598287f7c/element/0/value

{ "value": [ "webdriver" ] }

Firefox 来说,selenium webdriver 是基于这个平台开发的,WebDriver 实现了 FireFoxDriver,无需用户下载 FireFoxDriver。

chrome 需要,chromedriver.exe

IE 需要,IEDriverServer.exe

备注:年代久远的研究 appium 时的 wiz 保存下来的网页,出处原贴已找不到了。但对于分析研究 appium macaca 类似的工具原理应该有帮助,故分享出来。

比如 升级最新 macaca-cli 可以在http://localhost:3456/ 
看到目前 server 端支持的 webdriver 方法,那么通过看 macaca server --verbose 或脚本的 --verbose 日志,
我们也可以发现 大量的类似的这种请求

proxy.js:52:14 [master] pid:14960 Proxy: /wd/hub/session/temp/window:POST to http://localhost:9515/wd/hub/session/0f7e2af16cfbc92f86558c78618edfc8/window:POST with body: {"name":"CDwindow-EB102075-20E4-4CC4-8621-881F04FF0D3F"}

所以 底层上基本都相似的,也应该可以通过该方式尝试理解 macaca 的工作与封装处理流程。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 2 条回复 时间 点赞

点赞,明白了 selenium 的原理

您好,请问下上述 webdriver 的日志输出是从哪边看到的?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册