一尘不染

selenium 浏览器自动化中的执行流程

selenium

我不确定硒中的脚本(自动测试)执行情况。我
想这个过程如下:

  • 执行开始。
  • selenese命令转换为HTTP请求。
  • 浏览器驱动程序的HTTP服务器接收HTTP请求。
  • 浏览器驱动程序确定实现
  • 命令所需的步骤。
  • 浏览器驱动程序在浏览器上执行它们。
  • 执行状态将发送回浏览器驱动程序的HTTP服务器,然后发送回脚本(IDE)。
    我想这就是过程。请在我错的地方纠正我。

阅读 533

收藏
2020-06-26

共1个答案

一尘不染

在大胆和在箱子里是行动之人士,在斜体和箭头所使用的
协议。

当您想与浏览器互动时,

您的代码使用您所使用的语言(Java,Python,Ruby等)使用一个webdriver客户端(通常是一个库,例如)。selenium
该客户端与WebDriver服务器通信,并按照WebDriver协议发送和接收数据;该协议封装在http中,以便于传输和控制。
该webdriver的服务器将其转换为实际命令到浏览器 -所以它(浏览器)与页面交互,或者从中获取数据。
该流始终是端到端的(例如,浏览器从不直接
与您的代码通信:)),并且是双向的。故障/异常通常
只出现在代码的上游。

一些细节
该图中的“ 浏览器的webdriver ”是二进制文件(程序)
-Firefox 的“ geckodriver” (在Windows上带有“ .exe”),“ chromedriver”,
“ safaridriver”,“ edgedriver.exe” (始终与“ .exe” :))。它充当
代理-一方面接受并理解WebDriver
协议中的命令,另一方面-知道如何与浏览器进行通信。

webdriver始终是HTTP服务器-所有命令都封装在
HTTP中,并使用常规方法get / post / delete / put (如果与
常规REST 不同,则关闭)。它实现了webdriver
协议,因此客户端(selenium&co)具有
定义良好的API与之通信。因此,它也可以称为
“ WebDriver服务器”-它侦听命令,将其代理到浏览器,然后
将响应返回给客户端。(没有人这样称呼它:),但是它
使得区分“ webdriver可执行文件”和
“ webdriver协议” 变得更加容易。

作为服务器,它在本地 计算机或远程计算机上的随机网络端口上进行绑定和侦听
。如果您在本地运行,这就是
其二进制文件必须位于path变量中的原因-初始化时Selenium
启动它(因此它必须能够找到它)并获取它正在
侦听的网络端口(以进行进一步的通信)。如果您使用的是远程
连接,则必须a)知道远程webdriver
服务器的IP:port ,或b)使用“ Selenium Hub”,它在其
域下跟踪此信息并与您共享。

网络驱动程序服务器和浏览器之间的通信通常是二进制
rpc,并且非常特定于浏览器-它使用内部API,网络驱动程序
知道如何最好地控制此特定浏览器。因此,
驱动程序由浏览器供应商提供。这始终是本地(在
同一台机器/ OS中)通信(至少据我所知)。

如果您使用的是更高级别的框架,例如Robot Framework,Cucumber,
JBehave等,它位于该图中“您的代码”之前,试图使您
免受某些selenium调用的影响。

在实践中
“一张图片值一千个单词”,所以代码必须是740?
:)理论足够,这是一个实际示例:

from selenium import webdriver # importing selenium bindings

wd = webdriver.Firefox() # connect to the “webdriver server”, a local one
element = wd.find_element_by_css_selector(‘#my-id’) # locate an element
the_text = element.text # get is text

assert(text == ‘My awesome text!’) # verify it’s the expected one
这整个清单是您在第一部分中的代码 -为
完成工作而执行的不同指令,流程控制和检查。
在第1行,将selenium导入python的库以供进一步使用。

Selenium是
实现Webdriver协议的最流行的框架。它具有针对
不同语言的实现(即绑定)- 此处的
python
java
ruby
javascript
等。它努力做到的是为所有
这些接口提供统一的接口- getText()在Java中,Python也可以通过.text再次使用-
等等。通过此接口,它可以将客户端与实际的Webdriver
协议(用户类型)隔离开.text,并且无需关心该协议的实际
执行方式,也不必在协议更改时更改其代码。

在第3行webdriver上,实例化了一个对象;由于这里是一台
本地服务器,因此实例化过程将通过
前面所述的本地步骤-运行“ webdriver服务器”,现在知道其端口(并存储在
对象中)并且可以开始通信。

代码中的第4行使用该selenium方法
在页面中定位特定元素。在后台,该库将POST http请求发送到
webdriver服务器,以查找元素。
为什么要发布?因为一旦成功找到,服务器就会为其分配一个内部ID
,此后将使用该ID 。并将ID返回给客户端,客户端将
其存储为element对象的属性(*参见脚注)。
Webdriver服务器如何定位该元素?没办法-它
通过专有协议与浏览器通讯,说:“嘿,使用您的
呈现和评估引擎,在DOM中找到与此匹配的元素
CSS选择器,并给我提供参考,我们俩将来都可以重用。” (即
“魔术” :)。因此,这是由浏览器来完成的,webdriver
服务器只是代理通信。

让我们来谈谈细节- 第5行执行命令.text,该命令
显然会返回元素的文本(如果您不知道python,请不要
惊慌它是一条命令,但最后没有它()-这是一个
语言怪癖,作为对象属性的别名方法(非常方便的
功能)。
在这一点上,会发生什么:硒Python绑定这个命令匹配
了getElementText其通用接口; 然后将其与
webdriver协议命令 相匹配(打开链接,这很有趣,我保证) -它是GET类型,
其参数是this和that。
它打开到此端点的“ localhost:the_know_port”网络连接:

GET /session/2cce72b7-c748-48bc-b350-6dd6730b5a69/element/5/text

第一个“随机”字符串是会话ID-一个WebDriver服务器可以被
许多客户端使用,您的服务器将在第3行建立并存储。第二个
参数(“ 5”)是元素的ID,在第4行建立。出现
“文本”-您正在请求的子资源,该元素是受支持
的子资源之一。
这就是臭名昭著的Webdriver协议/ API-特定
访问方案的知识(您可以在
会话中获取已建立元素的“文本” )和流程(必须首先建立共享会话,然后再
引用元素) ,因此最终获得“文本”)。

之后,WebDriver服务器使浏览器从其DOM
(“魔力”)获取信息,并通过网络将其发送回客户端(selenium实例)

{"sessionId":"2cce72b7-c748-48bc-b350-6dd6730b5a69","status":0,"value":"My awesome text!"}
您的selenium实例正在等待响应,

从有效负载中获取并解析信息,然后将该值返回给您的代码-该变量
the_text现在的值为“ My awesome text!”。

并- 完成,该周期code -> webdriver client -> webdriver server -> browser -> webdriver server -> webdriver client -> code现在完成。

脚注:
(*)-这是令人恐惧的实际原因StaleElementReferenceException:所有这三个-客户端,WebDriver
服务器和浏览器都对DOM中的元素保持引用。
但是在某个特定的时刻,第3方-在浏览器中运行的javascript代码会更改/删除该元素,非常高兴地没有意识到某些引用现在使该引用无效(来考虑一下,这是很邪恶的行为:D)。
客户端下次尝试通过WebDriver服务器在浏览器中与引用进行交互时,该元素将不再存在。自然地,交互失败,失败返回上游到客户端,并且出现异常。其短信为“元素不再希望可以将它附加到DOM上。”

2020-06-26