Selenium WebDriver

Selenium 官網(wǎng)
Selenium WebDriver官網(wǎng)
webdriver實(shí)用指南python版本


WebDriver原理
WebDriver是按照Server-Client 的模式設(shè)計(jì)的。

Server就是 Remote Server,可以是任意的瀏覽器。當(dāng)我們的腳本啟動(dòng)瀏覽器后,該瀏覽器就是Remote Server,她的職責(zé)就是等待 Client 發(fā)送請(qǐng)求并做出響應(yīng)。

Client 端簡(jiǎn)單說(shuō)就是我們寫的測(cè)試腳本。腳本中的一些行為比如打開(kāi)瀏覽器,跳轉(zhuǎn)到指定的 URL 等操作就是以 http 請(qǐng)求的方式發(fā)送給被測(cè)試的瀏覽器,也就是Remote Server。Remote Server接受請(qǐng)求,執(zhí)行相應(yīng)操作,并在 Response中返回執(zhí)行狀態(tài)、返回值等信息。

Selenium 組成

Introducing WebDriver


作者注:WebDriver 可以看作是Selenium-RC替代品。所以現(xiàn)在學(xué)習(xí) Selenium 就不需要花時(shí)間專注于Selenium-RC了。

Selenium 2.0的主要新特性是WebDriver API的集成。WebDriver旨在提供一個(gè)更簡(jiǎn)單、更簡(jiǎn)潔的編程接口,以解決Selenium-RC API的一些限制。Selenium-WebDriver是為了更好地支持動(dòng)態(tài)web頁(yè)面而開(kāi)發(fā)的,頁(yè)面的元素在沒(méi)有頁(yè)面本身被重新加載的情況下可能會(huì)發(fā)生變化。WebDriver的目標(biāo)是提供一個(gè)設(shè)計(jì)良好的面向?qū)ο蟮腁PI,為現(xiàn)代高級(jí)web應(yīng)用程序測(cè)試問(wèn)題提供改進(jìn)的支持。

Selenium RC(Selenium 3.0版本移除了該模塊,以后還是使用 WebDriver 進(jìn)行腳本的編寫) 由Clent Libraies 和 Selenium Server組成:

Selenium Libraies 用于編寫測(cè)試腳本,支持多種不同的主流開(kāi)發(fā)語(yǔ)言,用來(lái)控制Selenium Server.

Selenium Server 則負(fù)責(zé)控制瀏覽器的行為,而Selenium Server 又由三部分組成:

  • Selenium Core:被Selenium Server 嵌入到瀏覽器頁(yè)面中,是一堆的JavaScript 函數(shù)的集合,通過(guò)這些JavaScript函數(shù)來(lái)實(shí)現(xiàn)對(duì)瀏覽器的操作。

  • Launcher:用于啟動(dòng)瀏覽器,把Selenium Core加載到瀏覽器頁(yè)面當(dāng)中,并把瀏覽器的代理設(shè)置Selenium Server 的Http Proxy。

  • Http Proxy:Selenium Server的http代理。

??

How Does WebDriver ‘Drive’ the Browser Compared to Selenium-RC?


Selenium-WebDriver使用每個(gè)瀏覽器對(duì)自動(dòng)化的本地支持直接調(diào)用瀏覽器。這些直接調(diào)用是如何生成的,它們支持的特性取決于您使用的瀏覽器。本章稍后將提供關(guān)于每個(gè)“瀏覽器驅(qū)動(dòng)程序”的信息。

對(duì)于那些熟悉Selenium-RC的人來(lái)說(shuō),這與您所習(xí)慣的完全不同。Selenium-RC對(duì)每個(gè)支持的瀏覽器都使用相同的方法。它在瀏覽器加載時(shí)將javascript函數(shù)注入瀏覽器,然后使用javascript在瀏覽器中驅(qū)動(dòng)AUT。WebDriver不使用這種技術(shù)。同樣,它直接驅(qū)動(dòng)瀏覽器使用內(nèi)置的支持自動(dòng)化的瀏覽器。

??

WebDriver and the Selenium-Server


您可能,也可能不需要Selenium服務(wù)器,這取決于您打算如何使用Selenium- webdriver。如果您的瀏覽器和測(cè)試都運(yùn)行在同一臺(tái)機(jī)器上,并且您的測(cè)試只使用WebDriver API,那么您就不需要運(yùn)行selenium服務(wù)器;WebDriver將直接運(yùn)行瀏覽器。

不過(guò),有一些原因可以使用selenium服務(wù)器和Selenium-WebDriver。

  • 您正在使用Selenium-Grid在多臺(tái)機(jī)器或虛擬機(jī)(vm)上分發(fā)測(cè)試。
  • 您希望連接到具有特定瀏覽器版本的遠(yuǎn)程機(jī)器,而不是當(dāng)前機(jī)器上的。
  • 您沒(méi)有使用Java綁定(例如Python、c#或Ruby),并希望使用 HtmlUnit Driver

Setting Up a Selenium-WebDriver Project


安裝Selenium意味著在開(kāi)發(fā)中建立項(xiàng)目,這樣您就可以使用Selenium編寫程序。如何做到這一點(diǎn)取決于您的編程語(yǔ)言和開(kāi)發(fā)環(huán)境。
這里只介紹如何將Selenium添加到Python環(huán)境
pip install selenium
或者是:
pip3 install selenium

Pip需要安裝 pip, Pip也依賴于 setuptools

至于如何將Selenium添加到其他語(yǔ)言環(huán)境中,請(qǐng)查閱Selenium WebDriver官網(wǎng)

至于已經(jīng)在使用 Selenium1.0的同學(xué)們?nèi)绾无D(zhuǎn)為使用Selenium WebDriver。請(qǐng)看官網(wǎng)介紹

??

Introducing the Selenium-WebDriver API by Example


WebDriver是一種用于自動(dòng)化web應(yīng)用程序測(cè)試的工具,特別是用于驗(yàn)證它們是否按預(yù)期工作。它的目標(biāo)是提供一個(gè)友好的API,易于探索和理解,比Selenium-RC (1.0) API更容易使用,這將有助于使您的測(cè)試更容易閱讀和維護(hù)。它不依賴于任何特定的測(cè)試框架,因此它可以在單元測(cè)試項(xiàng)目中或從簡(jiǎn)單的舊的“main”方法中使用。本節(jié)介紹WebDriver的API,并幫助您熟悉它。如果您還沒(méi)有建立一個(gè)WebDriver項(xiàng)目,那就開(kāi)始吧。這在前面的小節(jié)中描述過(guò),設(shè)置了一個(gè)Selenium-WebDriver項(xiàng)目。

一旦您的項(xiàng)目建立起來(lái),您可以看到WebDriver就像任何普通的庫(kù)一樣:它是完全自包含的,而且您通常不需要記住在使用它之前啟動(dòng)任何其他進(jìn)程或運(yùn)行任何安裝程序,而不是使用Selenium-RC的代理服務(wù)器。

注意: 使用 ChromeDriver, Opera Driver, Android Driver 以及 iOS Driver需要額外配置

from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
from selenium.webdriver.support import expected_conditions as EC # available since 2.26.0

# Create a new instance of the Firefox driver
driver = webdriver.Firefox()

# go to the google home page
driver.get("http://www.google.com")

# the page is ajaxy so the title is originally this:
print driver.title

# find the element that's name attribute is q (the google search box)
inputElement = driver.find_element_by_name("q")

# type in the search
inputElement.send_keys("cheese!")

# submit the form (although google automatically searches now without submitting)
inputElement.submit()

try:
    # we have to wait for the page to refresh, the last thing that seems to be updated is the title
    WebDriverWait(driver, 10).until(EC.title_contains("cheese!"))

    # You should see "cheese! - Google Search"
    print driver.title

finally:
    driver.quit()

其他腳本語(yǔ)言示例請(qǐng)參考

??

Selenium-WebDriver API Commands and Operations


??Fetching a Page(獲取某個(gè)頁(yè)面)


你可能想要做的第一件事是導(dǎo)航到一個(gè)頁(yè)面。通常的方法是通過(guò)調(diào)用get:
driver.get("http://www.google.com")

該腳本為 Python 腳本,其他語(yǔ)言腳本請(qǐng)參考

依賴于幾個(gè)因素,包括操作系統(tǒng)/瀏覽器組合,WebDriver可能會(huì)等待頁(yè)面加載。在某些情況下,WebDriver可以在頁(yè)面完成甚至開(kāi)始加載之前返回控件。為了確保健壯性,您需要等待在頁(yè)面中使用 Explicit and Implicit Waits
解釋:因?yàn)榫W(wǎng)絡(luò)環(huán)境的因素,每個(gè)頁(yè)面每次加載的時(shí)間會(huì)有所不同,如果在某一個(gè)頁(yè)面加載出來(lái)之前,腳本即執(zhí)行該頁(yè)面的某一個(gè)元素,則會(huì)報(bào)錯(cuò)。所以為了確保頁(yè)面已經(jīng)加載完畢再執(zhí)行,所以我們會(huì)在必要的時(shí)候使用 wait 命令。

??Locating UI Elements (WebElements)


在WebDriver中定位元素可以在WebDriver實(shí)例本身或WebElement上完成。每個(gè)語(yǔ)言綁定公開(kāi)一個(gè) “Find Element” and “Find Elements” 方法。前者返回與查詢匹配的WebElement對(duì)象,如果不能找到該元素,則拋出異常。后者返回一個(gè)WebElements列表,如果沒(méi)有DOM元素匹配查詢,則可能為空。

“Find”方法采用名為“By”的定位器或查詢對(duì)象。下面列出了“策略”。

作者注:DOM屬性
DOM 是 W3C(萬(wàn)維網(wǎng)聯(lián)盟)的標(biāo)準(zhǔn)。
屬性是節(jié)點(diǎn)(HTML 元素)的值,您能夠獲取或設(shè)置。

??By ID


這是定位一個(gè)元素最有效的方法。UI開(kāi)發(fā)人員所犯的常見(jiàn)錯(cuò)誤是在頁(yè)面上有非惟一id,或者自動(dòng)生成id,這兩個(gè)都應(yīng)該避免。html元素上的類比自動(dòng)生成的id更合適。

如果待測(cè)元素的源碼如下所示,我們?cè)撊绾味ㄎ荒兀?br> <div id="coolestWidgetEvah">...</div>
解釋:此處我們假設(shè)該元素是一個(gè)按鈕。該元素的 id 即為coolestWidgetEvah。就可以通過(guò) id 定位到該元素。除非某個(gè)元素沒(méi)有 id 這個(gè)屬性,一般我們都使用 id 定位元素。

以下使用 id定位 元素為 Python 腳本示例:

element = driver.find_element_by_id("coolestWidgetEvah")

或者

from selenium.webdriver.common.by import By
element = driver.find_element(by=By.ID, value="coolestWidgetEvah")

解釋:通過(guò)這兩個(gè)方法均可以定位到該按鈕,并將該方法返回的值賦值給變量 element,以便進(jìn)行其他操作。

其他語(yǔ)言腳本示例請(qǐng)參考

??By Class Name


本例中的“類”是指DOM元素上的屬性。通常在實(shí)際使用中,有許多具有相同類名的DOM元素,因此,查找第一個(gè)元素時(shí),找到多個(gè)元素成為更實(shí)際的選擇。

類似下面的待測(cè) web 頁(yè)面源碼,我們?nèi)绾问褂迷摲椒ǘㄎ辉啬兀?br> <div class="cheese"><span>Cheddar</span></div><div class="cheese"><span>Gouda</span></div>
解釋:該元素的 class(類)即 cheese。

Python 腳本如下:

cheeses = driver.find_elements_by_class_name("cheese")

或者

from selenium.webdriver.common.by import By
cheeses = driver.find_elements(By.CLASS_NAME, "cheese")

其他語(yǔ)言腳本請(qǐng)參考

??By Tag Name


元素的DOM標(biāo)記名。
類似下面的待測(cè) web 頁(yè)面源碼,我們?nèi)绾问褂迷摲椒ǘㄎ辉啬兀?br> <iframe src="..."></iframe>
Python 示例:

frame = driver.find_element_by_tag_name("iframe")

或者

from selenium.webdriver.common.by import By
frame = driver.find_element(By.TAG_NAME, "iframe")

其他腳本語(yǔ)言示例請(qǐng)參考

通過(guò) tag 識(shí)別某個(gè)元素的概率很低,例如我們打開(kāi)任意一個(gè)頁(yè)面,查看前端都會(huì)發(fā)現(xiàn)大量的<div>、<input>、<a>等等 tag。除非一個(gè)頁(yè)面只有這一個(gè)沒(méi)有重復(fù)的 tag,比如上述示例,<iframe>就是很少用的一個(gè) tag,如果一個(gè)頁(yè)面中只有這么一個(gè)<iframe>tag 那么就可以用 tag 定位。

??By Name


找到具有匹配名稱屬性的輸入元素。
類似下面的待測(cè) web 頁(yè)面源碼,我們?nèi)绾问褂迷摲椒ǘㄎ辉啬兀?br> <input name="cheese" type="text"/>
以下為 Python 示例:

cheese = driver.find_element_by_name("cheese")
或者

from selenium.webdriver.common.by import By
cheese = driver.find_element(By.NAME, "cheese")

其他腳本語(yǔ)言示例請(qǐng)參考

??By Link Text


找到與可見(jiàn)文本匹配的鏈接元素。
類似下面的待測(cè) web 頁(yè)面源碼,我們?nèi)绾问褂迷摲椒ǘㄎ辉啬兀?br> <a >cheese</a>>

以下為 Python 示例:

cheese = driver.find_element_by_link_text("cheese")

或者

from selenium.webdriver.common.by import By
cheese = driver.find_element(By.LINK_TEXT, "cheese")

比如百度主頁(yè)頂部的一行鏈接,如圖:

find_element_by_link_text("新聞").click().png

如果想要點(diǎn)擊“新聞”這個(gè)鏈接,那么就使用這個(gè)定位方法。

其他腳本語(yǔ)言示例請(qǐng)參考

??By Partial Link Text


找到帶有部分匹配可見(jiàn)文本的鏈接元素。

類似下面的待測(cè) web 頁(yè)面源碼,我們?nèi)绾问褂迷摲椒ǘㄎ辉啬兀?br> <a >search for cheese</a>>

以下為 Python 示例:

cheese = driver.find_element_by_partial_link_text("cheese")

或者

from selenium.webdriver.common.by import By
cheese = driver.find_element(By.PARTIAL_LINK_TEXT, "cheese")

比如百度主頁(yè)底部有一個(gè)比較長(zhǎng)的鏈接,如圖:


find_element_by_partial_link_text

這個(gè)鏈接的完整文本是“京公網(wǎng)安備11000002000001號(hào)”,我們使用部分文本,比如“京公網(wǎng)”就可以唯一確定是這個(gè)鏈接。此時(shí)就可以使用該定位方法。

??By CSS


顧名思義,它是css的定位策略。默認(rèn)情況下使用本機(jī)瀏覽器支持,所以請(qǐng)參考w3c css selectors,以獲得一般可用的css選擇器列表。如果瀏覽器沒(méi)有對(duì)css查詢的本機(jī)支持,則使用 Sizzle。IE6、7和FF3.0目前使用Sizzle作為css查詢引擎。

要注意的是,并非所有的瀏覽器都是相同的,有些css可能在一個(gè)版本中工作,但在另一個(gè)版本中可能無(wú)效。

比如下面查找“cheese”這個(gè)元素:

<div id="food"><span class="dairy">milk</span><span class="dairy aged">cheese</span></div>

python腳本示例:

cheese = driver.find_element_by_css_selector("#food span.dairy.aged")

解釋一下這個(gè)定位方法:

  • #表示通過(guò) id 屬性定位元素,因?yàn)?food 是一個(gè) id 屬性值,所以前面加一個(gè)#號(hào);
  • 通過(guò)標(biāo)簽名定位元素前面不加任何符號(hào)標(biāo)識(shí),直接使用標(biāo)簽名即可,因?yàn)?span 是一個(gè)標(biāo)簽名,所以前面什么都不加;
  • . 表示通過(guò) class 屬性定位元素,因?yàn)?dairy 是一個(gè) class 屬性值,所以前面加一個(gè).號(hào)。

這個(gè)腳本用的是多種方式的組合。通過(guò)一級(jí)級(jí)標(biāo)簽進(jìn)行最終的定位。我們還以百度主頁(yè)為例進(jìn)行舉例說(shuō)明。

  • 比如通過(guò) class 屬性定位到輸入框 這個(gè)元素:
    find_element_by_css_selector(".s_ipt")

  • 比如通過(guò) id 屬性定位到輸入框這個(gè)元素:
    find_element_by_css_selector("#kw")

  • 比如通過(guò)標(biāo)簽名定位(當(dāng)然這里不適用,標(biāo)簽名<input>不唯一):
    find_element_by_css_selector("input")
    通過(guò)組合定位就是:
    find_element_by_css_selector("input#kw")
    注意:這里 class 和 id 兩個(gè)屬性是同一級(jí)標(biāo)簽下的屬性,只使用一個(gè)。

為了更精確的定位,我們還可以使用剛精確的定位方式:
find_element_by_css_selector("div span input#kw")
這種組合方式還有很多,再舉一例:

browser.find_element_by_css_selector("form.fm span.bg.s_ipt_wr.quickdelete-wrap input.s_ipt").send_keys(u"簡(jiǎn)書")

注意: 最后在輸入框輸入漢字的時(shí)候在漢字前加了一個(gè)字母 u,如果不加則會(huì)造成漢字無(wú)法識(shí)別的錯(cuò)誤

或者

from selenium.webdriver.common.by import By
cheese = driver.find_element(By.CSS_SELECTOR, "#food span.dairy.aged")

??By XPath


在高層次上,WebDriver盡可能使用瀏覽器的本地XPath功能。在那些沒(méi)有本地XPath支持的瀏覽器上,我們提供了自己的實(shí)現(xiàn)。這可能導(dǎo)致一些意外的行為,除非您意識(shí)到不同的XPath引擎之間的差異。(總之一句話,不到別無(wú)選擇,不推薦使用 XPath 定位)。

Driver Tag and Attribute Name Attribute Values Native XPath Support
HtmlUnit Driver Lower-cased As they appear in the HTML Yes
Internet Explorer Driver Lower-cased As they appear in the HTML No
Firefox Driver Case insensitive As they appear in the HTML Yes

這是一個(gè)有點(diǎn)抽象的東西,所以對(duì)于下面這段HTML:

<input type="text" name="example" />
<INPUT type="text" name="other" />

python 腳本示例:

inputs = driver.find_elements_by_xpath("http://input")

或者

from selenium.webdriver.common.by import By
inputs = driver.find_elements(By.XPATH, "http://input")

將會(huì)找到以下的匹配數(shù):

XPath expression HtmlUnit Driver Firefox Driver Internet Explorer Driver
//input 1 (“example”) 2 2
//INPUT 0 2 0

有時(shí),HTML元素不需要顯式地聲明屬性,因?yàn)樗鼈儗⒛J(rèn)為已知值。例如,“input”標(biāo)簽不需要“type”屬性,因?yàn)樗J(rèn)為“text”。在WebDriver中使用xpath時(shí)的經(jīng)驗(yàn)法則是,您不應(yīng)該期望能夠與這些隱式屬性相匹配。

這里介紹一下“絕對(duì)路徑定位”方法,這個(gè)方法在定位元素走投無(wú)路的時(shí)候或許能幫助你。我們還是以百度首頁(yè)的輸入框?yàn)槔缦聢D:


絕對(duì)路徑定位

如果這個(gè)輸入框元素的屬性沒(méi)有 id,沒(méi)有 class,沒(méi)有name。咋辦,使用 tag 定位?你可以看到這個(gè)頁(yè)面不止一個(gè)<input>,不具有唯一性,所以無(wú)法使用 tag 定位。此時(shí)就可以使用絕對(duì)路徑定位。腳本如下:
find_element_by_xpath("/html/body/div/div[1]/div/div/div/form/span/input")

看起來(lái)就有點(diǎn)暈,我來(lái)解釋一下。

這里是通過(guò)標(biāo)簽定位,必須要從<html>開(kāi)始。<html>的下一級(jí)標(biāo)簽有<head>和<body>,這兩個(gè)標(biāo)簽是平級(jí)的,沒(méi)有父子之分,因?yàn)槲覀円ㄎ坏脑卦跇?biāo)簽<body>下,所以<html>之后是<body>。<body>之后又有兩個(gè)平級(jí)標(biāo)簽<script>和<div>,我們選擇<div>。但是這個(gè)<div>標(biāo)簽之后有多個(gè)平級(jí)標(biāo)簽<div>,上面截圖沒(méi)有體現(xiàn),看下圖:


CF8B84DD-ED3E-4588-A4C2-EFE53252F7B1.png


這個(gè)標(biāo)簽下有很多平級(jí)標(biāo)簽均未<div>,而我們要找的是第一個(gè)<div>,所以是<div>[1]。以此類推,直達(dá)定位到目標(biāo)元素。

注意:這種定位方法不到萬(wàn)不得已不使用,因?yàn)橐坏╉?yè)面有一點(diǎn)改動(dòng),定位就可能會(huì)出錯(cuò)。

??Using JavaScript


您可以執(zhí)行任意的javascript來(lái)找到一個(gè)元素,只要返回一個(gè)DOM元素,它就會(huì)自動(dòng)轉(zhuǎn)換成一個(gè)WebElement對(duì)象。

在具有jQuery的頁(yè)面上的簡(jiǎn)單示例:

java示例:

WebElement element = (WebElement) ((JavascriptExecutor)driver).executeScript("return $('.cheese')[0]");

python 示例:
element = driver.execute_script("return $('.cheese')[0]")

查找頁(yè)面上每個(gè)標(biāo)簽的所有輸入元素:

java示例:

List<WebElement> labels = driver.findElements(By.tagName("label"));
List<WebElement> inputs = (List<WebElement>) ((JavascriptExecutor)driver).executeScript(
    "var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){" +
    "inputs.push(document.getElementById(labels[i].getAttribute('for'))); } return inputs;", labels);

python 示例:

labels = driver.find_elements_by_tag_name("label")
inputs = driver.execute_script(
    "var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){" +
    "inputs.push(document.getElementById(labels[i].getAttribute('for'))); } return inputs;", labels)

??Getting text values


人們通常希望檢索元素中包含的innerText值。這會(huì)返回單個(gè)字符串值。注意,這只會(huì)返回頁(yè)面上顯示的可見(jiàn)文本。

python 示例:

element = driver.find_element_by_id("element_id")
element.text

??User Input - Filling In Forms


我們已經(jīng)看到了如何將文本輸入到文本區(qū)域或文本字段中,但是其他元素又如何呢?您可以“切換”復(fù)選框的狀態(tài),您可以使用“click”設(shè)置一些類似于選擇的選項(xiàng)標(biāo)記。處理選擇標(biāo)簽并不是很糟糕:

Python 腳本示例:

select = driver.find_element_by_tag_name("select")
allOptions = select.find_elements_by_tag_name("option")
for option in allOptions:
    print "Value is: " + option.get_attribute("value")
    option.click()

這將在頁(yè)面上找到第一個(gè)“SELECT”元素,然后依次遍歷每個(gè)選項(xiàng),打印出它們的值,然后依次選擇它們。您會(huì)注意到,這并不是處理SELECT元素的最有效方法。WebDriver的支持類包括一個(gè)名為“Select”的類,它提供了與這些類交互的有用方法。

python

# available since 2.12
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_tag_name("select"))
select.deselect_all()
select.select_by_visible_text("Edam")

這將從頁(yè)面上的第一個(gè)SELECT中取消所有選項(xiàng),然后選擇帶有“Edam”的顯示文本的選項(xiàng)。

填寫完表單后,您可能需要提交它。一種方法是找到“提交”按鈕并點(diǎn)擊它:

python

driver.find_element_by_id("submit").click()

Alternatively, WebDriver has the convenience method “submit” on every element. If you call this on an element within a form, WebDriver will walk up the DOM until it finds the enclosing form and then calls submit on that. If the element isn’t in a form, then the NoSuchElementException will be thrown:

python

element.submit()

??Moving Between Windows and Frames


一些web應(yīng)用程序有許多框架或多個(gè)窗口。WebDriver支持使用“切換”方法在指定的窗口之間移動(dòng):

driver.switch_to.window("windowName")

所有對(duì)驅(qū)動(dòng)程序的調(diào)用將被解釋為指向特定的窗口。但是你怎么知道窗戶的名字呢?看一下打開(kāi)的javascript或鏈接:

<a href="somewhere.html" target="windowName">Click here to open a new window</a>

或者,您可以將“窗口句柄”傳遞給“切換().window()”方法。知道了這一點(diǎn),就可以遍歷每個(gè)打開(kāi)的窗口:

python

for handle in driver.window_handles:
    driver.switch_to.window(handle)

作者注:HANDLE(句柄)是Windows操作系統(tǒng)中的一個(gè)概念。在Windows程序中,有各種各樣的資源(窗口、圖標(biāo)、光標(biāo)等),系統(tǒng)在創(chuàng)建這些資源時(shí)會(huì)為它們分配內(nèi)存,并返回標(biāo)示這些資源的標(biāo)示號(hào),即句柄。(摘自互動(dòng)百科)

??Popup Dialogs


從Selenium 2.0 beta 1開(kāi)始,構(gòu)建了支持處理彈出對(duì)話框的支持。在您觸發(fā)一個(gè)打開(kāi)彈出窗口的操作之后,您可以通過(guò)以下方式訪問(wèn)警報(bào):
python

alert = driver.switch_to.alert
# usage: alert.dismiss(), etc.

這將返回當(dāng)前打開(kāi)的警告對(duì)象。通過(guò)這個(gè)對(duì)象,您現(xiàn)在可以接受、解散、讀取它的內(nèi)容,甚至可以鍵入一個(gè)提示符。這個(gè)接口在警報(bào)、確認(rèn)和提示上同樣有效。更多信息請(qǐng)參考JavaDocs或RubyDocs。

??Navigation: History and Location


早些時(shí)候,我們使用“get”命令(driver.get(“http://www.example.com”)或driver.Url=“http://www.example.com”在c#中導(dǎo)航到一個(gè)頁(yè)面。如您所見(jiàn),WebDriver有許多較小的、面向任務(wù)的接口,導(dǎo)航是一項(xiàng)有用的任務(wù)。因?yàn)榧虞d頁(yè)面是一個(gè)基本的要求,所以在主WebDriver接口上執(zhí)行這個(gè)操作的方法,但是它只是一個(gè)同義詞:

python

driver.get("http://www.example.com")  # python doesn't have driver.navigate

重申:“導(dǎo)航(). To()”和“get()”做完全相同的事情。一個(gè)人比另一個(gè)更容易打字!

“導(dǎo)航”界面也暴露了在瀏覽器的歷史中來(lái)回移動(dòng)的能力:

python

driver.forward()
driver.back()

請(qǐng)注意,此功能完全依賴于底層瀏覽器。如果你習(xí)慣了一個(gè)瀏覽器的行為,那么你調(diào)用這些方法時(shí)可能會(huì)發(fā)生意想不到的事情。

??Cookies


在我們開(kāi)始下一步內(nèi)容之前,您可能會(huì)對(duì)如何使用cookie感興趣。首先,您需要在cookie將有效的域上。如果你想在開(kāi)始與網(wǎng)站交互之前預(yù)設(shè)cookie,而你的主頁(yè)是大的/需要一段時(shí)間來(lái)加載另一種選擇,那就是在網(wǎng)站上找到一個(gè)較小的頁(yè)面(通常是404頁(yè)面很小,例如http://example.com/some404page)。

Python

# Go to the correct domain
driver.get("http://www.example.com")

# Now set the cookie. Here's one for the entire domain
# the cookie name here is 'key' and its value is 'value'
driver.add_cookie({'name':'key', 'value':'value', 'path':'/'})
# additional keys that can be passed in are:
# 'domain' -> String,
# 'secure' -> Boolean,
# 'expiry' -> Milliseconds since the Epoch it should expire.

# And now output all the available cookies for the current URL
for cookie in driver.get_cookies():
    print "%s -> %s" % (cookie['name'], cookie['value'])

# You can delete cookies in 2 ways
# By name
driver.delete_cookie("CookieName")
# Or all of them
driver.delete_all_cookies()

??Changing the User Agent


這對(duì)于Firefox Driver來(lái)說(shuō)很簡(jiǎn)單:

python

profile = webdriver.FirefoxProfile()
profile.set_preference("general.useragent.override", "some UA string")
driver = webdriver.Firefox(profile)

??Drag And Drop


這里有一個(gè)使用action類來(lái)執(zhí)行拖放操作的示例。必須啟用本地事件。

python

from selenium.webdriver.common.action_chains import ActionChains
element = driver.find_element_by_name("source")
target =  driver.find_element_by_name("target")

ActionChains(driver).drag_and_drop(element, target).perform()

??

Driver Specifics and Tradeoffs


Selenium-WebDriver’s Drivers


WebDriver是測(cè)試應(yīng)該編寫的關(guān)鍵接口的名稱,但是有幾個(gè)實(shí)現(xiàn)。這些包括:
??HtmlUnit Driver


這是目前最快速、最輕量級(jí)的WebDriver實(shí)現(xiàn)。顧名思義,這是基于HtmlUnit的。HtmlUnit是一個(gè)沒(méi)有GUI的基于java的WebBrowser實(shí)現(xiàn)。對(duì)于任何語(yǔ)言綁定(除了java), Selenium服務(wù)器都需要使用這個(gè)驅(qū)動(dòng)程序。

????Usage


python

driver = webdriver.Remote("http://localhost:4444/wd/hub", webdriver.DesiredCapabilities.HTMLUNIT.copy())

????Pros


  • 最快的實(shí)現(xiàn)WebDriver
  • 純Java解決方案,因此它是平臺(tái)無(wú)關(guān)的。
  • 支持JavaScript.

????Cons


  • 模擬其他瀏覽器的JavaScript行為(見(jiàn)下面)

????JavaScript in the HtmlUnit Driver


沒(méi)有一個(gè)流行的瀏覽器使用HtmlUnit (Rhino)使用的JavaScript引擎。如果您使用HtmlUnit測(cè)試JavaScript,結(jié)果可能與那些瀏覽器有很大不同。

當(dāng)我們說(shuō)“JavaScript”時(shí),實(shí)際上是指“JavaScript和DOM”。雖然DOM是由W3C定義的,但是每個(gè)瀏覽器都有自己的特性和在DOM的實(shí)現(xiàn)上的差異,以及JavaScript如何與DOM交互。HtmlUnit有一個(gè)令人印象深刻的完整實(shí)現(xiàn)使用JavaScript DOM和具有良好的支持,但它是沒(méi)有不同于其他任何瀏覽器:它有自己的怪癖和差異來(lái)自W3C標(biāo)準(zhǔn)和主流瀏覽器的DOM實(shí)現(xiàn),盡管其模仿其他瀏覽器的能力。

有了WebDriver,我們必須做出選擇;我們是否啟用了HtmlUnit的JavaScript功能,并運(yùn)行那些只出現(xiàn)在那里的問(wèn)題的團(tuán)隊(duì)的風(fēng)險(xiǎn),或者我們是否禁用了JavaScript,知道有越來(lái)越多的站點(diǎn)依賴于JavaScript?我們采用了保守的方法,默認(rèn)情況下在使用HtmlUnit時(shí)禁用了支持。隨著WebDriver和HtmlUnit的每個(gè)版本的發(fā)布,我們重新評(píng)估這個(gè)決定:我們希望在HtmlUnit上默認(rèn)啟用JavaScript。

????Enabling JavaScript


If you can’t wait, enabling JavaScript support is very easy:

Python

driver = webdriver.Remote("http://localhost:4444/wd/hub", webdriver.DesiredCapabilities.HTMLUNITWITHJS)

這將導(dǎo)致HtmlUnit驅(qū)動(dòng)程序在默認(rèn)情況下模擬Firefox 3.6的JavaScript處理。

??Firefox Driver

使用Firefox插件控制 Firefox瀏覽器。使用的Firefox配置文件從安裝在機(jī)器上的內(nèi)容剝離出來(lái),只包含了Selenium WebDriver。xpi(插件)。默認(rèn)情況下,一些設(shè)置也會(huì)發(fā)生變化(參見(jiàn)源代碼,看看哪些是Firefox驅(qū)動(dòng)程序),F(xiàn)irefox驅(qū)動(dòng)程序可以在Windows、Mac和Linux上進(jìn)行測(cè)試。目前版本3.6, 10, latest - 1, latest。

????Usage


python

driver = webdriver.Firefox()

????Pros


????Cons


????修改Firefox配置文件


假設(shè)您想修改用戶代理字符串(如上所示),但是您已經(jīng)得到了一個(gè)包含幾十個(gè)有用擴(kuò)展的Firefox配置文件。獲取這個(gè)概要文件有兩種方法。假設(shè)該配置文件是使用Firefox的配置文件管理器(Firefox -ProfileManager)創(chuàng)建的:

java

ProfilesIni allProfiles = new ProfilesIni();
FirefoxProfile profile = allProfiles.getProfile("WebDriver");
profile.setPreferences("foo.bar", 23);
WebDriver driver = new FirefoxDriver(profile);

當(dāng)我們?cè)贔irefox Driver中開(kāi)發(fā)特性時(shí),我們就暴露了使用它們的能力。例如,在我們感覺(jué)本地事件在Firefox中是穩(wěn)定的Linux,在默認(rèn)情況下它們是禁用的。使他們:

python

profile = webdriver.FirefoxProfile()
profile.native_events_enabled = True
driver = webdriver.Firefox(profile)

????Info


請(qǐng)參閱wiki頁(yè)面中的Firefox部分,了解最新的信息。

??Internet Explorer Driver

InternetExplorerDriver是一個(gè)獨(dú)立的服務(wù)器,它實(shí)現(xiàn)了WebDriver的有線協(xié)議。這個(gè)驅(qū)動(dòng)程序已經(jīng)測(cè)試了ie7、8、9、10和11,并在Vista、Windows 7、Windows 8和Windows 8.1的適當(dāng)組合上進(jìn)行了測(cè)試。截至2014年4月15日,IE 6不再受支持。

驅(qū)動(dòng)程序支持運(yùn)行32位和64位版本的瀏覽器。如何確定在啟動(dòng)瀏覽器時(shí)使用哪個(gè)“bit-ness”取決于IEDriverServer的哪個(gè)版本。exe。如果是32位版本的IEDriverServer。exe啟動(dòng)后,IE的32位版本將啟動(dòng)。同樣,如果IEDriverServer的64位版本。exe啟動(dòng),將啟動(dòng)64位版本IE。

????Usage


Python

driver = webdriver.Ie()

????Pros(優(yōu)點(diǎn))


  • 在真正的瀏覽器中運(yùn)行并支持Javascript。

????Cons(缺點(diǎn))


  • 很明顯,InternetExplorerDriver只會(huì)在Windows上運(yùn)行!
  • 比較慢(雖然還是很時(shí)髦!)

????Info


查看wiki頁(yè)面的Internet Explorer部分 ,了解最新的信息。請(qǐng)?zhí)貏e注意所需的配置部分。

??

??ChromeDriver

ChromeDriver由Chromium項(xiàng)目維護(hù)/支持。WebDriver通過(guò)chromedriver二進(jìn)制文件(在chromium項(xiàng)目的下載頁(yè)面上找到)與Chrome合作。你需要安裝chromedriver和chrome瀏覽器的版本。chromedriver需要放在系統(tǒng)的路徑上,以便WebDriver自動(dòng)發(fā)現(xiàn)它。chromedriver在默認(rèn)安裝路徑中發(fā)現(xiàn)了Chrome瀏覽器本身。這些都可以被環(huán)境變量覆蓋。更多信息請(qǐng)參考 the wiki(維基百科)。

????Usage


Python

driver = webdriver.Chrome()

????Pros(優(yōu)點(diǎn))


  • 在真正的瀏覽器中運(yùn)行并支持JavaScript。

  • 因?yàn)镃hrome是一個(gè)基于webkit的瀏覽器,ChromeDriver可以讓你驗(yàn)證你的網(wǎng)站在Safari中運(yùn)行。注意,由于Chrome使用的是自己的V8 JavaScript引擎而不是Safari的Nitro引擎,JavaScript的執(zhí)行可能會(huì)有所不同。

????Cons(缺點(diǎn))


??

????Info


See our wiki,了解最新的信息。更多信息也可以在 downloads page
找到。

??

????Getting running with ChromeDriver


下載ChromeDriver可執(zhí)行文件,并遵循 wiki page上的其他說(shuō)明。

??

??Opera Driver

See the Opera Driver wiki article in the Selenium Wiki for information on using the Opera Driver.

??

??iOS Driver

See either the ios-driver or appium projects.

??

??Android Driver

See the Selendroid project

??

Alternative Back-Ends: Mixing WebDriver and RC Technologies


??WebDriver-Backed Selenium-RC


WebDriver的Java版本提供了Selenium-RC API的實(shí)現(xiàn)。這意味著您可以使用Selenium-RC API使用底層的WebDriver技術(shù)。這主要是為向后兼容性提供的。它允許使用Selenium-RC API的現(xiàn)有測(cè)試套件在覆蓋下使用WebDriver。它提供了幫助簡(jiǎn)化遷移到Selenium-WebDriver的路徑。同樣,這允許在相同的測(cè)試代碼中同時(shí)使用兩個(gè)api。

Selenium-WebDriver是這樣使用的:

java

// You may use any WebDriver implementation. Firefox is used here as an example
WebDriver driver = new FirefoxDriver();

// A "base url", used by selenium to resolve relative URLs
 String baseUrl = "http://www.google.com";

// Create the Selenium implementation
Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);

// Perform actions with selenium

selenium.open("http://www.google.com");
selenium.type("name=q", "cheese");
selenium.click("name=btnG");

// Get the underlying WebDriver implementation back. This will refer to the
// same WebDriver instance as the "driver" variable above.
WebDriver driverInstance = ((WebDriverBackedSelenium) selenium).getWrappedDriver();

//Finally, close the browser. Call stop on the WebDriverBackedSelenium instance
//instead of calling driver.quit(). Otherwise, the JVM will continue running after
//the browser has been closed.
selenium.stop();

????優(yōu)點(diǎn)(Pros)


  • 允許WebDriver和Selenium api共存。
  • 提供從Selenium RC API到WebDriver的管理遷移的簡(jiǎn)單機(jī)制。
  • 不需要運(yùn)行獨(dú)立的Selenium RC服務(wù)器嗎?

????缺點(diǎn)(Cons)


  • 不能實(shí)現(xiàn)每個(gè)方法
  • 更高級(jí)的Selenium使用(使用“browserbot”或來(lái)自Selenium Core的其他內(nèi)置JavaScript方法)可能不起作用。
  • 由于底層實(shí)現(xiàn)差異,一些方法可能會(huì)比較慢。

??Backing WebDriver with Selenium


WebDriver不像Selenium RC那樣支持很多瀏覽器,所以為了在使用WebDriver API時(shí)提供支持,您可以使用SeleneseCommandExecutor。

以這種方式支持Safari,并使用以下代碼(確保禁用彈出式阻塞):

java(官方文檔只提供了 JAVA 示例):

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setBrowserName("safari");
CommandExecutor executor = new SeleneseCommandExecutor(new URL("http://localhost:4444/"), new URL("http://www.google.com/"), capabilities);
WebDriver driver = new RemoteWebDriver(executor, capabilities);

目前,這種方法存在一些主要的局限性,尤其是findElements不像預(yù)期的那樣工作。另外,由于我們使用Selenium Core來(lái)驅(qū)動(dòng)瀏覽器,所以您受到JavaScript sandbox的限制。

??

運(yùn)行獨(dú)立的Selenium服務(wù)器,用于遠(yuǎn)程驅(qū)動(dòng)程序(Running Standalone Selenium Server for use with RemoteDrivers)


Selenium的下載頁(yè)面下載selenium-server-standalone-<version>。jar和可選IEDriverServer。如果您計(jì)劃使用Chrome,請(qǐng)從 Google Code下載。

打開(kāi)IEDriverServer和/或chromedriver,并將它們放在$PATH / %PATH%上的目錄中—Selenium服務(wù)器應(yīng)該能夠處理對(duì)IE / Chrome的請(qǐng)求,而無(wú)需進(jìn)行額外的修改。

在命令行上啟動(dòng)服務(wù)器
java -jar <path_to>/selenium-server-standalone-<version>.jar

如果您想要使用本機(jī)事件功能,請(qǐng)?jiān)诿钚猩鲜褂迷撨x項(xiàng)指示此功能

-Dwebdriver.enable.native.events=1

對(duì)于其他命令行選項(xiàng),執(zhí)行

java -jar <path_to>/selenium-server-standalone-<version>.jar -help

為了正常運(yùn)行,應(yīng)該允許以下端口進(jìn)入TCP連接:4444、7054-5(或者是您計(jì)劃運(yùn)行的并發(fā)實(shí)例數(shù)量的兩倍)。在Windows下,您可能還需要打開(kāi)應(yīng)用程序。

Additional Resources


你可以在 WebDriver’s wiki中找到更多的WebDriver資源。

當(dāng)然,不要猶豫,在任何Selenium主題上進(jìn)行internet搜索,包括Selenium- webdriver的驅(qū)動(dòng)程序。有很多關(guān)于Selenium的博客,以及許多用戶論壇上的帖子。另外,Selenium User’s Group是一個(gè)很好的資源。
http://groups.google.com/group/selenium-users

Next Steps


這一章簡(jiǎn)單地介紹了WebDriver及其一些關(guān)鍵功能。一旦熟悉了Selenium-WebDriver API,您就會(huì)想要學(xué)習(xí)如何構(gòu)建可維護(hù)性、可擴(kuò)展性和降低脆弱性的測(cè)試套件。大多數(shù)Selenium專家現(xiàn)在建議的方法是使用頁(yè)面對(duì)象設(shè)計(jì)模式(Page Object Design Pattern)和可能的頁(yè)面工廠(Page Factory)來(lái)設(shè)計(jì)測(cè)試代碼。通過(guò)在Java和c#中提供一個(gè)PageFactory類,Selenium-WebDriver提供了支持。在 next chapter中,我們將介紹這一主題,以及其他高級(jí)主題。另外,對(duì)于該技術(shù)的高級(jí)描述,您可能需要查看 Test Design Considerations chapter。這兩章都介紹了通過(guò)使測(cè)試代碼更模塊化編寫更易于維護(hù)的測(cè)試的技術(shù)。

Next topic


WebDriver: Advanced Usage

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容