我不确定硒中的脚本(自动测试)执行情况。我 想这个过程如下:
在大胆和在箱子里是行动之人士,在斜体和箭头所使用的 协议。
当您想与浏览器互动时,
您的代码使用您所使用的语言(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现在完成。
code -> webdriver client -> webdriver server -> browser -> webdriver server -> webdriver client -> code
脚注: (*)-这是令人恐惧的实际原因StaleElementReferenceException:所有这三个-客户端,WebDriver 服务器和浏览器都对DOM中的元素保持引用。 但是在某个特定的时刻,第3方-在浏览器中运行的javascript代码会更改/删除该元素,非常高兴地没有意识到某些引用现在使该引用无效(来考虑一下,这是很邪恶的行为:D)。 客户端下次尝试通过WebDriver服务器在浏览器中与引用进行交互时,该元素将不再存在。自然地,交互失败,失败返回上游到客户端,并且出现异常。其短信为“元素不再希望可以将它附加到DOM上。”
StaleElementReferenceException