目录

1. Selenium的历史

2. WebDriver协议

3. Selenium驱动浏览器原理

4. 测试代码与Webdriver的交互

5. Webdriver与浏览器的关系

6. Selenium Webdriver总结

7. 客户端和浏览器在同一台机器上

8. 客户端远程驱动浏览器

9. selenium多机运行配置


1. Selenium的历史

Selenium1

早期的Selenium1.x使用的是Javascript注入技术与浏览器打交道,需要Selenium RC启动一个Server,将操作Web元素的API调用转化为一段段Javascript,在Selenium内核启动浏览器之后注入这段Javascript。开发过Web应用的人都知道,Javascript可以获取并调用页面的任何元素,自如的进行操作。由此才实现了Selenium的目的:自动化Web操作。这种Javascript注入技术的缺点是速度不理想,而且稳定性大大依赖于Selenium内核对API翻译成的Javascript质量高低。

Selenium2

相比于selenium1.x,selenium2.x版本整合了webdriver以及原版selenium。两个项目合二为一,虽然名字还叫selenium,但也可以叫Webdriver。

当Selenium2.x 提出了WebDriver的概念之后,它提供了完全另外的一种方式与浏览器交互。那就是利用浏览器原生的API,封装成一套更加面向对象的Selenium WebDriver API,直接操作浏览器页面里的元素,甚至操作浏览器本身(截屏,窗口大小,启动,关闭,安装插件,配置证书之类的)。由于使用的是浏览器原生的API,速度大大提高,而且调用的稳定性交给了浏览器厂商本身,显然是更加科学。然而带来的一些副作用就是,不同的浏览器厂商,对Web元素的操作和呈现多少会有一些差异,这就直接导致了Selenium WebDriver要分浏览器厂商不同,而提供不同的实现。例如Firefox就有专门的FirefoxDriver,Chrome就有专门的ChromeDriver(甚至包括了AndroidDriver和iOS WebDriver)。

Selenium3

其实相对于与Selenium2,Selenium3没有做太多的改动。下面给出官方的文档说明,供参考。

官方文档描述如下:

We aim for Selenium 3 to be “a tool for user-focused automation of mobile and web apps”.

What does this mean? For mobile users, the Selenium project will be hosting a suite of tests to facilitate interoperability between the many different projects available that are extending the WebDriver API to also cope with mobile. Developers from projects such as Appium, ios-driver and selendroid will be working on the suite of tests to enable this.

We’ll also be working on making the technology behind Selenium as stable and capable as possible. For this reason, Selenium 3 will see the removal of the original Selenium Core implementations, and consequently we’ll be deprecating the RC APIs too. The old versions will still be available as a separate download, but active development will cease, except for very urgent fixes. We will still be providing an implementation of the RC APIs backed by WebDriver, so you can continue running your existing tests, but now would be a great time to make the move to using the WebDriver APIs directly.

所以对于Selenium3来说最大的变动可能就是更加专注于手机和web的测试,尤其是手机的支持。

Selenium 3将删除最初的Selenium核心实现,官方不再推荐使用RC API。旧版本仍然可以单独下载,但是除了非常紧急的修复之外,活跃的开发将停止。官方仍将提供一个由WebDriver支持的RC API的实现,因此可以继续运行现有的测试,但官方推荐以后使用WebDriver API。

对于Selenium2中对于RemotControl的实现我看了下Selenium3的源码发现确实不在支持,而更多的转向了W3C standard,

2. WebDriver协议

WebDriver是W3C的一个标准,由Selenium主持。具体的协议标准可以从官方网站查看。

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

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

官方网站文档描述如下:

The following table of endpoints lists the method and URI template for each endpoint node command. Extension commands are implicitly appended to this table.

Method URI Template Command
POST /session New Session
DELETE /session/{session id} Delete Session
GET /status Status
GET /session/{session id}/timeouts Get Timeouts
POST /session/{session id}/timeouts Set Timeouts
POST /session/{session id}/url Navigate To
GET /session/{session id}/url Get Current URL
POST /session/{session id}/back Back
POST /session/{session id}/forward Forward
POST /session/{session id}/refresh Refresh
GET /session/{session id}/title Get Title
GET /session/{session id}/window Get Window Handle
DELETE /session/{session id}/window Close Window
POST /session/{session id}/window Switch To Window
GET /session/{session id}/window/handles Get Window Handles
POST /session/{session id}/window/new New Window
POST /session/{session id}/frame Switch To Frame
POST /session/{session id}/frame/parent Switch To Parent Frame
GET /session/{session id}/window/rect Get Window Rect
POST /session/{session id}/window/rect Set Window Rect
POST /session/{session id}/window/maximize Maximize Window
POST /session/{session id}/window/minimize Minimize Window
POST /session/{session id}/window/fullscreen Fullscreen Window
GET /session/{session id}/element/active Get Active Element
POST /session/{session id}/element Find Element
POST /session/{session id}/elements Find Elements
POST /session/{session id}/element/{element id}/element Find Element From Element
POST /session/{session id}/element/{element id}/elements Find Elements From Element
GET /session/{session id}/element/{element id}/selected Is Element Selected
GET /session/{session id}/element/{element id}/attribute/{name} Get Element Attribute
GET /session/{session id}/element/{element id}/property/{name} Get Element Property
GET /session/{session id}/element/{element id}/css/{property name} Get Element CSS Value
GET /session/{session id}/element/{element id}/text Get Element Text
GET /session/{session id}/element/{element id}/name Get Element Tag Name
GET /session/{session id}/element/{element id}/rect Get Element Rect
GET /session/{session id}/element/{element id}/enabled Is Element Enabled
GET /session/{session id}/element/{element id}/computedrole Get Computed Role
GET /session/{session id}/element/{element id}/computedlabel Get Computed Label
POST /session/{session id}/element/{element id}/click Element Click
POST /session/{session id}/element/{element id}/clear Element Clear
POST /session/{session id}/element/{element id}/value Element Send Keys
GET /session/{session id}/source Get Page Source
POST /session/{session id}/execute/sync Execute Script
POST /session/{session id}/execute/async Execute Async Script
GET /session/{session id}/cookie Get All Cookies
GET /session/{session id}/cookie/{name} Get Named Cookie
POST /session/{session id}/cookie Add Cookie
DELETE /session/{session id}/cookie/{name} Delete Cookie
DELETE /session/{session id}/cookie Delete All Cookies
POST /session/{session id}/actions Perform Actions
DELETE /session/{session id}/actions Release Actions
POST /session/{session id}/alert/dismiss Dismiss Alert
POST /session/{session id}/alert/accept Accept Alert
GET /session/{session id}/alert/text Get Alert Text
POST /session/{session id}/alert/text Send Alert Text
GET /session/{session id}/screenshot Take Screenshot
GET /session/{session id}/element/{element id}/screenshot Take Element Screenshot
POST /session/{session id}/print Print Page

3. Selenium驱动浏览器原理

在我们创建一个WebDrive实例的过程中,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我们希望浏览器接下来做社么事情。

使用Selenium实现驱动浏览器,主要涉及三个东西。

  • 测试代码

测试代码就是程序员利用不同的语言和相应的selenium API库完成的代码。本文将以python为例进行说明。

  • Webdriver

Webdriver是针对不同的浏览器开发的,不同的浏览器有不同的webdriver。例如针对Chrome使用的chromedriver。

  • 浏览器

浏览器和相应的Webdriver对应。

首先我们来看一下这三个部分的关系。
对于三个部分的关系模型,可以用一个日常生活中常见的例子来类比。

对于打的这个行为来说,乘客和出租车司机进行交互,告诉出租车想去的目的地,出租车司机驾驶汽车把乘客送到目的地,这样乘客就乘坐出租车到达了自己想去的地方。
这和Webdriver的实现原理是类似的,测试代码中包含了各种期望的对浏览器界面的操作,例如点击。测试代码通过给Webdriver发送指令,让Webdriver知道想要做的操作,而Webdriver根据这些操作在浏览器界面上进行控制,由此测试代码达到了在浏览器界面上操作的目的。
理清了Selenium自动化测试三个重要组成之间的关系,接下来我们来具体分析其中一个最重要的关系。

4. 测试代码与Webdriver的交互

接下来我会以获取界面元素这个基本的操作为例来分析两者之间的关系。
在测试代码中,我们第一步要做的是新建一个webdriver类的对象:

from selenium import webdriver
driver = webdriver.Chrome()

这里新建的driver对象是一个webdriver.Chrome()类的对象,而webdriver.Chrome()类的本质是

from .chrome.webdriver import WebDriver as Chrome

也就是一个来自chrome的WebDriver类。这个.chrome.webdriver.WebDriver是继承了selenium.webdriver.remote.webdriver.WebDriver

from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
...
class WebDriver(RemoteWebDriver):"""Controls the ChromeDriver and allows you to drive the browser.You will need to download the ChromeDriver executable fromhttp://chromedriver.storage.googleapis.com/index.html"""def __init__(self, executable_path="chromedriver", port=0,chrome_options=None, service_args=None,desired_capabilities=None, service_log_path=None):
...

以python为例,在selenium库中,通过ID获取界面元素的方法是这样的:

from selenium import webdriver
driver = webdriver.Chrome()
driver.find_element_by_id(id)

find_elements_by_idselenium.webdriver.remote.webdriver.WebDriver类的实例方法。在代码中,我们直接使用的其实不是selenium.webdriver.remote.webdriver.WebDriver这个类,而是针对各个浏览器的webdriver类,例如webdriver.Chrome()
所以说在测试代码中执行各种浏览器操作的方法其实都是selenium.webdriver.remote.webdriver.WebDriver类的实例方法。
接下来我们再深入selenium.webdriver.remote.webdriver.WebDriver类来看看具体是如何实现例如find_element_by_id()的实例方法的。
通过Source code可以看到:

    def find_element(self, by=By.ID, value=None):"""'Private' method used by the find_element_by_* methods.:Usage:Use the corresponding find_element_by_* instead of this.:rtype: WebElement"""if self.w3c:...return self.execute(Command.FIND_ELEMENT, {'using': by,'value': value})['value']

这个方法最后call了一个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}

正如注释中提到的一样,其中的关键在于

response = self.command_executor.execute(driver_command, params)

一个名为command_executor的对象执行了execute方法。
名为command_executor的对象是RemoteConnection类的对象,并且这个对象是在新建selenium.webdriver.remote.webdriver.WebDriver类对象的时候就完成赋值的self.command_executor = RemoteConnection(command_executor, keep_alive=keep_alive)
结合selenium.webdriver.remote.webdriver.WebDriver类的类注释来看:

class WebDriver(object):"""Controls a browser by sending commands to a remote server.This server is expected to be running the WebDriver wire protocolas defined athttps://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol:Attributes:- session_id - String ID of the browser session started and controlled by this WebDriver.- capabilities - Dictionaty of effective capabilities of this browser session as returnedby the remote server. See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities- command_executor - remote_connection.RemoteConnection object used to execute commands.- error_handler - errorhandler.ErrorHandler object used to handle errors."""_web_element_cls = WebElementdef __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',desired_capabilities=None, browser_profile=None, proxy=None,keep_alive=False, file_detector=None):

WebDriver类的功能是通过给一个remote server发送指令来控制浏览器。而这个remote server是一个运行WebDriver wire protocol的server。而RemoteConnection类就是负责与Remote WebDriver server的连接的类。
可以注意到有这么一个新建WebDriver类的对象时候的参数command_executor,默认值='http://127.0.0.1:4444/wd/hub'。这个值表示的是访问remote server的URL。因此这个值作为了RemoteConnection类的构造方法的参数,因为要连接remote server,URL是必须的。
现在再来看RemoteConnection类的实例方法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' % commanddata = utils.dump_json(params)path = string.Template(command_info[1]).substitute(params)url = '%s%s' % (self._url, path)return self._request(command_info[0], url, body=data)

这个方法有两个参数:

  • command
  • params

command表示期望执行的指令的名字。通过观察self._commands这个dict可以看到,self._commands存储了selenium.webdriver.remote.command.Command类里的常量指令和WebDriver wire protocol中定义的指令的对应关系。

self._commands = {Command.STATUS: ('GET', '/status'),Command.NEW_SESSION: ('POST', '/session'),Command.GET_ALL_SESSIONS: ('GET', '/sessions'),Command.QUIT: ('DELETE', '/session/$sessionId'),
...Command.FIND_ELEMENT: ('POST', '/session/$sessionId/element'),

以FIND_ELEMENT为例可以看到,指令的URL部分包含了几个组成部分:

  • HTTP请求方法。WebDriver wire protocol中定义的指令是符合RESTful规范的,通过不同请求方法对应不同的指令操作。

  • sessionId。Session的概念是这么定义的:

    The server should maintain one browser per session. Commands sent to a session will be directed to the corresponding browser.

    也就是说sessionId表示了remote server和浏览器的一个会话,指令通过这个会话变成对于浏览器的一个操作。

  • element。这一部分用来表示具体的指令。

selenium.webdriver.remote.command.Command类里的常量指令又在各个具体的类似find_elements的实例方法中作为execute方法的参数来使用,这样就实现了selenium.webdriver.remote.webdriver.WebDriver类中实现各种操作的实例方法与WebDriver wire protocol中定义的指令的一一对应。
selenium.webdriver.remote.webelement.WebElement中各种在WebElement上的操作也是用类似的原理实现的。

实例方法execute的另一个参数params则是用来保存指令的参数的,这个参数将转化为JSON格式,作为HTTP请求的body发送到remote server。
remote server在执行完对浏览器的操作后得到的数据将作为HTTP Response的body返回给测试代码,测试代码经过解析处理后得到想要的数据。

5. Webdriver与浏览器的关系

这一部分属于各个浏览器开发者和Webdriver开发者的范畴,所以我们不需要太关注,我们所关心的主要还是测试代码和Webdriver的关系,就好像出租车驾驶员如何驾驶汽车我们不需要关心一样。

6. Selenium Webdriver总结


最后通过这个关系图来简单的描述Selenium三个组成部分的关系。通过对python selenium库的分析,希望能够帮助大家对selenium和webdriver的实现原理有更进一步的了解,在日常的自动化脚本开发中更加快捷的定位问题和解决问题。

7. 客户端和浏览器在同一台机器上

from selenium import webdriver
import time
browser=webdriver.Chrome()
browser.get("http://www.baidu.com")

(1).browser=webdriver.Chrome()这句代码的解析如下:

通过上面代码的解析,我们已经知道我们创建了一个实例browser,该实例是WebDriver和RemoteWebDriver共同拥有的实例。通过WebDriver启动了chromedriver程序,通过RemoteWebDriver则启动了浏览器,生成session值。并规定了webdriver协议。

(2).driver.get("http://www.google.com")这句代码的解析:

该get()方法是RemoteWebDriver的方法。该方法直接又调用了RemoteWebDriver的execute()方法。execute()方法就是用来操作浏览器做各种事情的。

我们的测试代码向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端进行交互。

8. 客户端远程驱动浏览器

通过上面的实例和以前介绍的内容,我们知道了,客户端按照webdriver协议编写一段字符串,这段字符串再通过json的方式发送到浏览器端,浏览器端则使用chromedriver驱动程序启动浏览器并跟据发送过来的字符串操作浏览器进行相应的工作。

所以,我们想远程驱动浏览器,我们需要有程序去启动chromedriver程序。然后我们再在客户端json一段字符串过去。

如果不考虑remote模式,开启一个Selenium浏览器实例应该是类似这样。

driver = selenium.webdriver.Firefox()

但是Remote模式下,就要稍微复杂一点儿:

具体步骤:

1.下载合适的selenium-server,并启动

目的:启动chromedriver和设置监听端口

在win中:

下载地址:https://selenium-release.storage.googleapis.com/index.html?path=3.3/

下载建议:根据您当前的selenium版本下载对应的selenium server版本

在cmd中执行命令:

>> java -Dwebdriver.chrome.driver = “/opt/chromium-browser/chromedriver.exe ” -jar selenium-server-standalone-3.3.1.jar -port 9999

在linux中:

npm install -g selenium-standalone
selenium-standalone install
selenium-standalone start

2.编写客户端代码,如下:

from selenium.webdriver.remote import webdriver   #这儿直接导入的remote里面的webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities   #导入浏览器的基本参数
f=webdriver.WebDriver(command_executor="http://192.168.1.103:9999/wd/hub",desired_capabilities=DesiredCapabilities.CHROME)
f.get("http://www.baidu.com")

看出这段代码和上面《一、客户端和浏览器在同一台机器上》里面的代码有什么不同了吗?

上面实例化的是chrome 里面的webdriver 。而该实例里实例化的是remote里面的webdriver。这是为什么呢?

因:上面需要启动chromedriver和设置监听端口。而该实例里面启动chromedriver和设置监听端口是在远程服务器端通过selenium-server启动的。

9. selenium多机运行配置

多机版(真正的remote模式),需要定义两个角色:hub(即Master)、node(即Slave)。

要在其它node主机执行,必须满足以下几个条件:

具体怎么用,可以看帮助。

看所有的一级选项:

java -jar selenium-server-standalone-3.3.1.jar --help

看hub特性:

java -jar selenium-server-standalone-3.3.1.jar -role hub -help

看node特性:

java -jar selenium-server-standalone-3.3.1.jar -role node --help

启动hub很简单:

java -jar selenium-server-standalone-3.3.1.jar -role hub

启动node稍微复杂点儿,必须指定hub地址、端口:

java -jar selenium-server-standalone-3.3.1.jar -role node -port 5555 -hub http://10.120.9.222:4444/grid/register

最新版的selenium Grid允许同时并行的,在不同的环境运行多个测试任务。

【环境准备】

1.需要两台PC机,两台机器必须安装好jdk的环境变量(我的一个win10,一个win8)
2.需要一个selenium-server-standalone-3.11.0.jar包。
3.安装了python2.7(64位),selenium3.5(这两个版本不是很重要,都可以)

【配置开始】

1.集线器主服务(A ip:192.168.1.108)
Selenium Grid需要一台机子作为集线器,即启动主服务器,找到jar包所在的目录,按住shift键然后点击右键,选择‘在此处打开窗口’打开命令窗口,通过这个命令启动主服务,即hub服务:

java -jar selenium-server-standalone-3.11.0.jar  -role  hub

命令执行完后输出,有一个注册中心地址:http://192.168.1.108:4444/grid/register/:

如果不设置端口号,默认的端口号是4444,如果要改这个端口,可以再上面的命令后面加上 -port XXXX。启动完后,你可以用浏览器打开 http://localhost:4444/grid/console 这个网址查看主节点的状态。

2.节点服务(B ip:192.168.1.110)
启动完主服务hub之后,接下来做的是启动子节点,以另一台机器作为子节点的机器:

java -jar selenium-server-standalone-3.11.0.jar -role node -hub  http://192.168.1.108:4444/grid/register/

服务启动后输出:

启动完成连接到主节点后,可以在主节A机子上 ,http://localhost:4444/grid/console网址查看到这个子节点状态。使用同样的方法,可以链接其它的子节点B、C…

【代码测试】

在主机A上运行测试的代码,会把命令发送给B:

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
d=DesiredCapabilities.CHROME.copy()
d['browserName']='chrome'
d['version']='65'
desired_cap={'browserName':'chrome',
'version':'65',
'javascriptEnabled':True}
driver=webdriver.Remote(command_executor='http://192.168.1.110:5555/wd/hub',desired_capabilities=d)
driver.get("http://192.168.1.108:8080/lab/stusign")
printdriver.title
driver.quit()

总结:

1.整体来说这个多机并行的环境搭建还是很容易的,参考官方文档就可以很轻松的搞定。
2.问题在于我们实际的工作工程中如何使用良好的策略来规则化我们的多机并行执行呢?还有就是执行的内容是用例脚本,而这些脚本是以何种规则分配到对应的机器上呢?这种问题,只能说具体情况具体分析。
3.就是我们在启动节点时,启动命令华友一些附加的参数如:-D、-config、-browser等等,你可以用java -jar selenium-server-standalone-3.11.0.jar -h去看具体的解释。
示例(好好研究下参数的意义):

java -jar selenium-server-standalone-3.11.0.jar -role node -hub http://192.168.1.108:4444/grid/register/-browser “browserName=chrome,maxinstance=1,platform=WINDOWS” -Dwebdriver.chrome.driver=D://chromedriver.exe

 有兴趣可以关注我的微信公众号“自动化测试全栈”,微信号:QAlife,学习更多自动化测试技术。

也可加入我们的自动化测试技术交流群,QQ群号码:301079813

主要探讨loadrunner/JMeter测试、Selenium/RobotFramework/Appium自动化测试、接口自动化测试,测试工具等测试技术,让我们来这里分享经验、交流技术、结交朋友、拓展视野、一起奋斗!

参考文章:

1.关于对Selenium的理解_Ant Ren的专栏-CSDN博客

2.Selenium源码分析之WebDriver_Ant Ren的专栏-CSDN博客_selenium源码、

3.透过源码看本质-关于Selenium Webdriver 实现原理的一点思考和分享

4.WebDriver 工作原理

5.Python Selenium3 WebDriver Remote

6.【Python】selenium多机运行配置

Selenium Webdriver原理终于搞清楚了相关推荐

  1. selenium webdriver 原理概述

    背景 虽然掌握selenium webdriver提供的各种方法,就可以做web的UI自动化,但是本着知其然,也要知其所以然的态度,也为了提升自己.了解下selenium webdriver的原理是必 ...

  2. python爬虫工程师 成长之路八 Selenium WebDriver

    文章目录 Selenium WebDriver 简介 Selenium WebDriver 原理 Selenium WebDriver 安装 Selenium WebDriver 使用 浏览器常用操作 ...

  3. python webdriver点击指令_测开系列Selenium Webdriver Python(20)--Webdriver运行原理

    Webdriver运行原理 转帖请注明出处!谢谢 在开发Webdriver的自动化脚本过程中,Webdriver后台在创建WebDriver实例的过程中,先确认浏览器的原生组件中是否存在可匹配的版本. ...

  4. 曲鸟全栈UI自动化教学(四):Selenium工作原理及Webdriver对浏览器的配置和操作

    一.前言 上篇文章我们学习了Selenium页面操作原理及如何高效的进行元素定位 那Selenium的工作原理又是什么?是如何驱动浏览器的呢?这篇文章为你讲解Selenium工作原理及Webdrive ...

  5. selenium原理python_通过python Selenium 库源代码来看Selenium Webdriver 实现原理

    作为一名使用Selenium开发UI自动化多年的工程师,一直都对Selenium Webdriver的实现原理感觉不是很清楚.怎么就通过脚本控制浏览器进行各种操作了呢?相信很多Selenium的使用者 ...

  6. Selenium Webdriver 的使用java执行js代码 解决 ScriptEngine不支持浏览器内置对象window,document的问题

    问题场景: 使用java 掉用js代码,发现 ScriptEngine不支持浏览器内置对象window,document的问题: 问题一:为什么要 用java掉用js代码? 比如在 抓取(爬取)对方网 ...

  7. WebDriver原理分析

    WebDriver原理分析 WebDriver与之前Selenium的JS注入实现不同,直接利用了浏览器native support来操作浏览器.所以对于不同平台,不同的浏览器,必须依赖一个特定的浏览 ...

  8. 终于搞明白gluPerspective和gluLookAt的关系了

    2019独角兽企业重金招聘Python工程师标准>>> 终于搞明白gluPerspective和gluLookAt的关系了 函数原型 gluLookAt(GLdoble eyex,G ...

  9. 【自动化测试爬虫系列】Selenium Webdriver 介绍

    一. Selenium Webdriver技术介绍 1. 简介 selenium Webdriver是一套针对不同浏览器而开发的web应用自动化测试代码库.使用这套库可以进行页面的交互操作,并且可以重 ...

最新文章

  1. 初学架构设计的第一步:需求、愿景与架构
  2. java keytool生成证书_使用JDK自带的工具keytool生成证书
  3. 青蛙学Linux—MySQL备份工具XtraBackup
  4. 剑指offer面试题23:从上到下打印二叉树(树的层序遍历)
  5. Django日志信息路径的设置
  6. idea实用快捷键_idea万能快捷键,你不知道的17个实用技巧!!!
  7. Seurat的单细胞免疫组库分析来了!
  8. 无心剑中译雪莱诗14首
  9. 【讨论】不得不重视的问题:信息太多!信息太杂!
  10. PDE6 Transport with decay
  11. 使用SQL语句获得服务器名称和IP 地址
  12. solidworks工程图模板与图纸格式的区别_教你DWG如何导入为图纸格式
  13. linux下使用hash_map及STL总结
  14. 小插件,通过js实现邮箱自动提示功能
  15. 为什么DMA方式的优先级高于程序中断方式
  16. 线粒体可以进行个体识别?
  17. 什么是同城双活、异地双活、异地多活
  18. 经典小游戏(密室逃脱全集+答案)
  19. 安卓扫描银行卡获取卡号信息
  20. matlab求三维图形表面积,基于MATLAB的不规则平面立体表面积计算

热门文章

  1. 使用时间超级长的充电宝是啥样的?
  2. 皮一皮:泡沫面膜,直男慎送此礼物...
  3. Spring Security 实战干货:客户端OAuth2授权请求的入口在哪里
  4. 跟踪了下CSDN博客之星的竞选数据,我就看看不评论,你怎么看?
  5. Python 获 Mozilla 和扎克伯格夫妇 40 余万美金资助
  6. 自律到极致-人生才精致:第12期
  7. php swoole process,Swoole_process实现进程池的方法
  8. android webview腾讯,Android webview无法播放腾讯视频问题
  9. 计算机基础16秋在线作业,北大16秋《计算机基础与应用-第二组》在线作业.doc
  10. mysql数据类型不写(),MYSQL 数据类型