webdriver协议

何为协议?协议就是客户端和服务器规定好的通信方式。
web driver协议规定了某一个操作(比如find_element_by_id),客户端需要向服务器的哪个路由(其实是通过command来定义的接口地址)接口发送怎样的数据格式以及响应的数据。
协议是抽象类,只规定了有哪些操作和怎样的数据格式,没有具体的实现,具体的实现是由不同的服务器来实现的,比如浏览器驱动、appium服务器,相同的操作对不同的服务器来说调用的接口和传递的参数是相同的,因为这是协议规定的;然而具体的实现是由服务器特定的功能决定的,浏览器驱动是用来操作浏览器的,appium是用来操作手机设备的,具体实现肯定是不同。

appium

appium扩展了selenium,它可以用selenium所有的接口,因为appium服务器也具体实现了其功能,所以可以兼容使用(服务器接口和接收的参数由协议规定)。

selenium/appium怎么向服务器发送请求

这一切都发动自selenium webdriver类中的execute这个方法

    def execute(self, driver_command, params=None):"""Sends a command to be executed by a command.CommandExecutor.:Args:- driver_command: The name of the command to execute as a string.- params: A dictionary of named parameters to send with the command.:Returns:The command's JSON response loaded into a dictionary object."""if self.session_id is not None:if not params:params = {'sessionId': self.session_id}elif 'sessionId' not in params:params['sessionId'] = self.session_idparams = self._wrap_value(params)response = self.command_executor.execute(driver_command, params)if response:self.error_handler.check_response(response)response['value'] = self._unwrap_value(response.get('value', None))return response# If the server doesn't send a response, assume the command was# a successreturn {'success': 0, 'value': None, 'sessionId': self.session_id}

其中调用了command_executor.execute方法

    def execute(self, command, params):"""Send a command to the remote server.Any path subtitutions required for the URL mapped to the command should beincluded in the command parameters.:Args:- command - A string specifying the command to execute.- params - A dictionary of named parameters to send with the command asits JSON payload."""command_info = self._commands[command]assert command_info is not None, 'Unrecognised command %s' % commandpath = string.Template(command_info[1]).substitute(params)if hasattr(self, 'w3c') and self.w3c and isinstance(params, dict) and 'sessionId' in params:del params['sessionId']data = utils.dump_json(params)url = '%s%s' % (self._url, path)return self._request(command_info[0], url, body=data)
    def _request(self, method, url, body=None):"""Send an HTTP request to the remote server.:Args:- method - A string for the HTTP method to send the request with.- url - A string for the URL to send the request to.- body - A string for request body. Ignored unless method is POST or PUT.:Returns:A dictionary with the server's parsed JSON response."""LOGGER.debug('%s %s %s' % (method, url, body))parsed_url = parse.urlparse(url)headers = self.get_remote_connection_headers(parsed_url, self.keep_alive)resp = Noneif body and method != 'POST' and method != 'PUT':body = Noneif self.keep_alive:resp = self._conn.request(method, url, body=body, headers=headers)statuscode = resp.statuselse:http = urllib3.PoolManager(timeout=self._timeout)resp = http.request(method, url, body=body, headers=headers)statuscode = resp.statusif not hasattr(resp, 'getheader'):if hasattr(resp.headers, 'getheader'):resp.getheader = lambda x: resp.headers.getheader(x)elif hasattr(resp.headers, 'get'):resp.getheader = lambda x: resp.headers.get(x)data = resp.data.decode('UTF-8')try:if 300 <= statuscode < 304:return self._request('GET', resp.getheader('location'))if 399 < statuscode <= 500:return {'status': statuscode, 'value': data}content_type = []if resp.getheader('Content-Type') is not None:content_type = resp.getheader('Content-Type').split(';')if not any([x.startswith('image/png') for x in content_type]):try:data = utils.load_json(data.strip())except ValueError:if 199 < statuscode < 300:status = ErrorCode.SUCCESSelse:status = ErrorCode.UNKNOWN_ERRORreturn {'status': status, 'value': data.strip()}# Some of the drivers incorrectly return a response# with no 'value' field when they should return null.if 'value' not in data:data['value'] = Nonereturn dataelse:data = {'status': 0, 'value': data}return datafinally:LOGGER.debug("Finished Request")resp.close()

最终发送请求的是_request这个方法。
在selenium webdriver中的execute中最后用_unwrap_value包装了下返回的响应,放在了response['value']中。

看看服务器路由接口的定义

self._commands = {Command.STATUS: ('GET', '/status'),Command.NEW_SESSION: ('POST', '/session'),Command.GET_ALL_SESSIONS: ('GET', '/sessions'),Command.QUIT: ('DELETE', '/session/$sessionId'),Command.GET_CURRENT_WINDOW_HANDLE:('GET', '/session/$sessionId/window_handle'),Command.W3C_GET_CURRENT_WINDOW_HANDLE:('GET', '/session/$sessionId/window'),Command.GET_WINDOW_HANDLES:('GET', '/session/$sessionId/window_handles'),Command.W3C_GET_WINDOW_HANDLES:('GET', '/session/$sessionId/window/handles'),Command.GET: ('POST', '/session/$sessionId/url'),Command.GO_FORWARD: ('POST', '/session/$sessionId/forward'),Command.GO_BACK: ('POST', '/session/$sessionId/back'),Command.REFRESH: ('POST', '/session/$sessionId/refresh'),Command.EXECUTE_SCRIPT: ('POST', '/session/$sessionId/execute'),Command.W3C_EXECUTE_SCRIPT:('POST', '/session/$sessionId/execute/sync'),Command.W3C_EXECUTE_SCRIPT_ASYNC:('POST', '/session/$sessionId/execute/async'),Command.GET_CURRENT_URL: ('GET', '/session/$sessionId/url'),Command.GET_TITLE: ('GET', '/session/$sessionId/title'),Command.GET_PAGE_SOURCE: ('GET', '/session/$sessionId/source'),Command.SCREENSHOT: ('GET', '/session/$sessionId/screenshot'),Command.ELEMENT_SCREENSHOT: ('GET', '/session/$sessionId/element/$id/screenshot'),Command.FIND_ELEMENT: ('POST', '/session/$sessionId/element'),Command.FIND_ELEMENTS: ('POST', '/session/$sessionId/elements'),Command.W3C_GET_ACTIVE_ELEMENT: ('GET', '/session/$sessionId/element/active'),Command.GET_ACTIVE_ELEMENT:('POST', '/session/$sessionId/element/active'),Command.FIND_CHILD_ELEMENT:('POST', '/session/$sessionId/element/$id/element'),Command.FIND_CHILD_ELEMENTS:('POST', '/session/$sessionId/element/$id/elements'),Command.CLICK_ELEMENT: ('POST', '/session/$sessionId/element/$id/click'),Command.CLEAR_ELEMENT: ('POST', '/session/$sessionId/element/$id/clear'),Command.SUBMIT_ELEMENT: ('POST', '/session/$sessionId/element/$id/submit'),Command.GET_ELEMENT_TEXT: ('GET', '/session/$sessionId/element/$id/text'),Command.SEND_KEYS_TO_ELEMENT:('POST', '/session/$sessionId/element/$id/value'),Command.SEND_KEYS_TO_ACTIVE_ELEMENT:('POST', '/session/$sessionId/keys'),Command.UPLOAD_FILE: ('POST', "/session/$sessionId/file"),Command.GET_ELEMENT_VALUE:('GET', '/session/$sessionId/element/$id/value'),Command.GET_ELEMENT_TAG_NAME:('GET', '/session/$sessionId/element/$id/name'),Command.IS_ELEMENT_SELECTED:('GET', '/session/$sessionId/element/$id/selected'),Command.SET_ELEMENT_SELECTED:('POST', '/session/$sessionId/element/$id/selected'),Command.IS_ELEMENT_ENABLED:('GET', '/session/$sessionId/element/$id/enabled'),Command.IS_ELEMENT_DISPLAYED:('GET', '/session/$sessionId/element/$id/displayed'),Command.GET_ELEMENT_LOCATION:('GET', '/session/$sessionId/element/$id/location'),Command.GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW:('GET', '/session/$sessionId/element/$id/location_in_view'),Command.GET_ELEMENT_SIZE:('GET', '/session/$sessionId/element/$id/size'),Command.GET_ELEMENT_RECT:('GET', '/session/$sessionId/element/$id/rect'),Command.GET_ELEMENT_ATTRIBUTE:('GET', '/session/$sessionId/element/$id/attribute/$name'),Command.GET_ELEMENT_PROPERTY:('GET', '/session/$sessionId/element/$id/property/$name'),Command.GET_ALL_COOKIES: ('GET', '/session/$sessionId/cookie'),Command.ADD_COOKIE: ('POST', '/session/$sessionId/cookie'),Command.GET_COOKIE: ('GET', '/session/$sessionId/cookie/$name'),Command.DELETE_ALL_COOKIES:('DELETE', '/session/$sessionId/cookie'),Command.DELETE_COOKIE:('DELETE', '/session/$sessionId/cookie/$name'),Command.SWITCH_TO_FRAME: ('POST', '/session/$sessionId/frame'),Command.SWITCH_TO_PARENT_FRAME: ('POST', '/session/$sessionId/frame/parent'),Command.SWITCH_TO_WINDOW: ('POST', '/session/$sessionId/window'),Command.CLOSE: ('DELETE', '/session/$sessionId/window'),Command.GET_ELEMENT_VALUE_OF_CSS_PROPERTY:('GET', '/session/$sessionId/element/$id/css/$propertyName'),Command.IMPLICIT_WAIT:('POST', '/session/$sessionId/timeouts/implicit_wait'),Command.EXECUTE_ASYNC_SCRIPT: ('POST', '/session/$sessionId/execute_async'),Command.SET_SCRIPT_TIMEOUT:('POST', '/session/$sessionId/timeouts/async_script'),Command.SET_TIMEOUTS:('POST', '/session/$sessionId/timeouts'),Command.DISMISS_ALERT:('POST', '/session/$sessionId/dismiss_alert'),Command.W3C_DISMISS_ALERT:('POST', '/session/$sessionId/alert/dismiss'),Command.ACCEPT_ALERT:('POST', '/session/$sessionId/accept_alert'),Command.W3C_ACCEPT_ALERT:('POST', '/session/$sessionId/alert/accept'),Command.SET_ALERT_VALUE:('POST', '/session/$sessionId/alert_text'),Command.W3C_SET_ALERT_VALUE:('POST', '/session/$sessionId/alert/text'),Command.GET_ALERT_TEXT:('GET', '/session/$sessionId/alert_text'),Command.W3C_GET_ALERT_TEXT:('GET', '/session/$sessionId/alert/text'),Command.SET_ALERT_CREDENTIALS:('POST', '/session/$sessionId/alert/credentials'),Command.CLICK:('POST', '/session/$sessionId/click'),Command.W3C_ACTIONS:('POST', '/session/$sessionId/actions'),Command.W3C_CLEAR_ACTIONS:('DELETE', '/session/$sessionId/actions'),Command.DOUBLE_CLICK:('POST', '/session/$sessionId/doubleclick'),Command.MOUSE_DOWN:('POST', '/session/$sessionId/buttondown'),Command.MOUSE_UP:('POST', '/session/$sessionId/buttonup'),Command.MOVE_TO:('POST', '/session/$sessionId/moveto'),Command.GET_WINDOW_SIZE:('GET', '/session/$sessionId/window/$windowHandle/size'),Command.SET_WINDOW_SIZE:('POST', '/session/$sessionId/window/$windowHandle/size'),Command.GET_WINDOW_POSITION:('GET', '/session/$sessionId/window/$windowHandle/position'),Command.SET_WINDOW_POSITION:('POST', '/session/$sessionId/window/$windowHandle/position'),Command.SET_WINDOW_RECT:('POST', '/session/$sessionId/window/rect'),Command.GET_WINDOW_RECT:('GET', '/session/$sessionId/window/rect'),Command.MAXIMIZE_WINDOW:('POST', '/session/$sessionId/window/$windowHandle/maximize'),Command.W3C_MAXIMIZE_WINDOW:('POST', '/session/$sessionId/window/maximize'),Command.SET_SCREEN_ORIENTATION:('POST', '/session/$sessionId/orientation'),Command.GET_SCREEN_ORIENTATION:('GET', '/session/$sessionId/orientation'),Command.SINGLE_TAP:('POST', '/session/$sessionId/touch/click'),Command.TOUCH_DOWN:('POST', '/session/$sessionId/touch/down'),Command.TOUCH_UP:('POST', '/session/$sessionId/touch/up'),Command.TOUCH_MOVE:('POST', '/session/$sessionId/touch/move'),Command.TOUCH_SCROLL:('POST', '/session/$sessionId/touch/scroll'),Command.DOUBLE_TAP:('POST', '/session/$sessionId/touch/doubleclick'),Command.LONG_PRESS:('POST', '/session/$sessionId/touch/longclick'),Command.FLICK:('POST', '/session/$sessionId/touch/flick'),Command.EXECUTE_SQL:('POST', '/session/$sessionId/execute_sql'),Command.GET_LOCATION:('GET', '/session/$sessionId/location'),Command.SET_LOCATION:('POST', '/session/$sessionId/location'),Command.GET_APP_CACHE:('GET', '/session/$sessionId/application_cache'),Command.GET_APP_CACHE_STATUS:('GET', '/session/$sessionId/application_cache/status'),Command.CLEAR_APP_CACHE:('DELETE', '/session/$sessionId/application_cache/clear'),Command.GET_NETWORK_CONNECTION:('GET', '/session/$sessionId/network_connection'),Command.SET_NETWORK_CONNECTION:('POST', '/session/$sessionId/network_connection'),Command.GET_LOCAL_STORAGE_ITEM:('GET', '/session/$sessionId/local_storage/key/$key'),Command.REMOVE_LOCAL_STORAGE_ITEM:('DELETE', '/session/$sessionId/local_storage/key/$key'),Command.GET_LOCAL_STORAGE_KEYS:('GET', '/session/$sessionId/local_storage'),Command.SET_LOCAL_STORAGE_ITEM:('POST', '/session/$sessionId/local_storage'),Command.CLEAR_LOCAL_STORAGE:('DELETE', '/session/$sessionId/local_storage'),Command.GET_LOCAL_STORAGE_SIZE:('GET', '/session/$sessionId/local_storage/size'),Command.GET_SESSION_STORAGE_ITEM:('GET', '/session/$sessionId/session_storage/key/$key'),Command.REMOVE_SESSION_STORAGE_ITEM:('DELETE', '/session/$sessionId/session_storage/key/$key'),Command.GET_SESSION_STORAGE_KEYS:('GET', '/session/$sessionId/session_storage'),Command.SET_SESSION_STORAGE_ITEM:('POST', '/session/$sessionId/session_storage'),Command.CLEAR_SESSION_STORAGE:('DELETE', '/session/$sessionId/session_storage'),Command.GET_SESSION_STORAGE_SIZE:('GET', '/session/$sessionId/session_storage/size'),Command.GET_LOG:('POST', '/session/$sessionId/log'),Command.GET_AVAILABLE_LOG_TYPES:('GET', '/session/$sessionId/log/types'),Command.CURRENT_CONTEXT_HANDLE:('GET', '/session/$sessionId/context'),Command.CONTEXT_HANDLES:('GET', '/session/$sessionId/contexts'),Command.SWITCH_TO_CONTEXT:('POST', '/session/$sessionId/context'),Command.FULLSCREEN_WINDOW:('POST', '/session/$sessionId/window/fullscreen'),Command.MINIMIZE_WINDOW:('POST', '/session/$sessionId/window/minimize')}

上面这些command只是selenium中的,appium还有自己增加的command
在appium中的webdriver类中有_addCommands这个方法,这个方法会遍历所有的父类,只要父类也有_addCommands方法,则执行一遍,所以appium初始化后的command会更多,接口也就更多,这也就是说其扩展了selenium。

    def _addCommands(self):# call the overridden command binders from all mixin classesfor mixin_class in filter(lambda x: x is not self.__class__, self.__class__.__mro__):if hasattr(mixin_class, self._addCommands.__name__):getattr(mixin_class, self._addCommands.__name__, None)(self)self.command_executor._commands[Command.TOUCH_ACTION] = \('POST', '/session/$sessionId/touch/perform')self.command_executor._commands[Command.MULTI_ACTION] = \('POST', '/session/$sessionId/touch/multi/perform')self.command_executor._commands[Command.GET_CURRENT_PACKAGE] = \('GET', '/session/$sessionId/appium/device/current_package')self.command_executor._commands[Command.SET_IMMEDIATE_VALUE] = \('POST', '/session/$sessionId/appium/element/$id/value')self.command_executor._commands[Command.LAUNCH_APP] = \('POST', '/session/$sessionId/appium/app/launch')self.command_executor._commands[Command.CLOSE_APP] = \('POST', '/session/$sessionId/appium/app/close')self.command_executor._commands[Command.END_TEST_COVERAGE] = \('POST', '/session/$sessionId/appium/app/end_test_coverage')self.command_executor._commands[Command.RESET] = \('POST', '/session/$sessionId/appium/app/reset')self.command_executor._commands[Command.OPEN_NOTIFICATIONS] = \('POST', '/session/$sessionId/appium/device/open_notifications')self.command_executor._commands[Command.REPLACE_KEYS] = \('POST', '/session/$sessionId/appium/element/$id/replace_value')self.command_executor._commands[Command.GET_SETTINGS] = \('GET', '/session/$sessionId/appium/settings')self.command_executor._commands[Command.UPDATE_SETTINGS] = \('POST', '/session/$sessionId/appium/settings')self.command_executor._commands[Command.LOCATION_IN_VIEW] = \('GET', '/session/$sessionId/element/$id/location_in_view')self.command_executor._commands[Command.CLEAR] = \('POST', '/session/$sessionId/element/$id/clear')

小节

  1. 协议是抽象类,只规定了操作、接口和传参数据格式。
  2. appium扩展了selenium,appium服务器也实现了selenium的接口功能,只是实现方式不同,当然也有appium特有的功能接口(web不具备的,手机具备的特有功能)。
  3. 所有的操作在客户端,最终都通过execute方法来请求服务器,并封装响应。

再讨论下webdriver相关推荐

  1. 再讨论下古老的include

    再讨论下古老的include,做c/c++局域网聊天编程的对我们都知道#include指令都不会陌生,绝大多数也都知道如何使用,但我相信仍有人对此是一知半解, C: 我们都知道#include C++ ...

  2. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  3. java一球从100米高度自由落下,每次落地后反跳回原高度的一半再落下, 求它在第10次落地时,共经过多少米

    一球从100米高度自由落下,每次落地后反跳回原高度的一半再落下, 求它在第10次落地时,共经过多少米 本人对于此题分析 求第十次落地 共经过多少米 第一次球落地为100米 所以球只弹了九次 而且每一次 ...

  4. 装修的200条小常识,有心得的来讨论下了

    装修的200条小常识,有心得的来讨论下了 1.鞋柜的隔板不要做到头,留一点空间好让鞋子的灰能漏到最底层,水槽和燃气灶上方装灯.定卫生间地漏的位置时一定要先想好,量好尺寸.地漏最好位于砖的一边,如果在砖 ...

  5. 一个球从100米高度自由落下,每次落地后反弹回原高度的一半; * 再落下,求在第几次之后反弹高度小于0.1米, * 并计算在这一次落地时共经过多少米?...

    package com.db2;/*** 一个球从100米高度自由落下,每次落地后反弹回原高度的一半: * 再落下,求在第几次之后反弹高度小于0.1米,* 并计算在这一次落地时共经过多少米?* * @ ...

  6. ACMNO.14一球从M米高度自由下落,每次落地后返回原高度的一半,再落下。 它在第N次落地时反弹多高?共经过多少米? 保留两位小数 输入 M N 输出 它在第N次落地时反弹多高?共经过多少米

    题目描述 一球从M米高度自由下落,每次落地后返回原高度的一半,再落下.它在第N次落地时反弹多高?共经过多少米? 保留两位小数 输入 M N 输出 它在第N次落地时反弹多高?共经过多少米? 保留两位小数 ...

  7. /* * 编程第二题(20分): 一球从100米高度自由落下,每次落地后反跳回原高度的一半,再落下。求它在第十次落地时,共经过多少米?第十次反弹多高? */

    题目: /* * 编程第二题(20分): 一球从100米高度自由落下,每次落地后反跳回原高度的一半,再落下.求它在第十次落地时,共经过多少米?第十次反弹多高? */ 我是用java做的 public ...

  8. android子线程没有运行完,android假如主线程依赖子线程A的执行结果,如何让A执行完成,之后主线程再往下执行呢?...

    /* String ObjectResult="原先的结果"; //使用VOLLY框架(与问题无关) JsonObjectRequest jsonObjectRequest = n ...

  9. 一球从M米高度自由下落,每次落地后返回原高度的一半,再落下。 它在第N次落地时反弹多高?共经过多少米? 保留两位小数...

    问题 1019: [编程入门]自由下落的距离计算 时间限制: 1Sec 内存限制: 128MB 提交: 7252 解决: 4190 题目描述 一球从M米高度自由下落,每次落地后返回原高度的一半,再落下 ...

最新文章

  1. java bufferedimage颜色_使用BufferedImage进行渐变色操作
  2. IEEE史上首位华人主席,马里兰大学终身教授刘国瑞当选
  3. 机器学习100天:专栏目录
  4. 隐藏与显现_手机键盘摇一摇,隐藏功能立马显现,太棒了
  5. 记录---基于BigDecimal的特殊的四舍五入
  6. UnityEngine.UI.dll is in timestamps but is not known in assetdatabase
  7. 您是哪一种类型的老板?
  8. Unity3D_(插件)小地图自刷新制作Minimap小地图
  9. 英特尔® 处理器显卡
  10. 使用u盘安装linux操作系统原理
  11. PMP课程笔记:第7章 项目成本管理
  12. Maven 环境变量配置
  13. python数组a减去数组b的简便操作
  14. 四种插头类型:XH、VH、SM、HY
  15. 什么样的游戏最适合GameFi?
  16. Android给Activity取消title标题
  17. CSS3中的伪元素选择器与scss
  18. kdbp是什么文件_DVF文件扩展名 - 什么是.dvf以及如何打开? - ReviverSoft
  19. python无法启动0xc0000022_无法正常启动0xc0000022?0xc0000022一键修复教程
  20. 电商项目_ads层建设

热门文章

  1. python考勤分析
  2. linux基础命令学习之mv(7)
  3. jquery extend中
  4. Virtual Machine Manager 2012 R2利用服务模板部署SQL
  5. RDIFramework.NET(.NET快速信息化系统开发框架) Web版介绍
  6. 用JSLint+Ant检验HTML代码
  7. HttpHandler解析并展示PDF文档内容
  8. 难道真的是RedBook错了?
  9. linux中安装,编译时调用,运行时调用,更新共享库
  10. ssh整合步骤之二(架构设计)