selenium2自動化測試實戰--基於Python語言

自動化測試基礎

1、 軟件測試分類

1.1 根據項目流程階段劃分軟件測試

1.1.1 單元測試

  單元測試(或模塊測試)是對程序中的單個子程序或具備獨立功能的代碼段進行測試的過程。javascript

1.1.2 集成測試

  集成測試是在單元測試的基礎上,先經過單元模塊組裝成系統或子系統,再進行測試。重點是檢查模塊之間的接口是否正確。css

1.1.3 系統測試

  系統測試是針對整個產品系統進行的測試,驗證系統是否知足需求規格的定義,以及軟件系統的正確性和性能等是否知足其需求規格的要求。html

1.1.4 驗收測試

  驗收測試是部署軟件以前的最後一個測試階段。驗收測試的目的是確保軟件準備就緒,向軟件購買者展現該軟件系統可以知足用戶的需求。前端

1.2 白盒測試、黑盒測試、灰盒測試

  白盒測試與黑盒測試,主要是根據軟件測試工做中對軟件代碼的可見程度進行的劃分。這也是軟件測試領域中最基本的概念之一。java

1.2.1 黑盒測試

  黑盒測試,指的是把被測的軟件看作一個黑盒子,咱們不去關心盒子裏面的結構是什麼樣子的,只關心軟件的輸入數據和輸出結果。python

  它只檢查程序呈現給用戶的功能是否按照需求規格說明書的規定正常使用、程序是否能接受輸入數據併產生正確的輸出信息。黑盒測試着眼於程序外部結構,不考慮內部邏輯結構,主要針對軟件界面和軟件功能進行測試。android

1.2.2 白盒測試

  白盒測試,指的是把盒子打開,去研究裏面的源代碼和程序執行結果。git

  它是按照程序內部的結構測試程序,經過測試來檢驗產品內部動做是否按照設計規格說明書的規定正常進行,檢驗程序中的每條邏輯路徑是否都能按預約要求正確工做。github

1.2.3 灰盒測試

  灰盒測試介於黑盒測試和白盒測試之間。web

  能夠這樣理解,灰盒測試既關注輸出對於輸入的正確性,同時也關注內部表現。但這種關注不像白盒測試那樣詳細、完整,它只是經過一些表徵性的現象、事件、標誌來判斷內部的運行狀態。有時候輸出是正確的,但內部其實已經錯誤了,這種狀況很是多。若是每次都經過白盒測試來操做,效率會很低,所以須要採起灰盒測試的方法。

 

1.3 功能測試與性能測試

  從軟件的不一樣測試面能夠劃分爲功能測試與性能測試

1.3.1 功能測試

  功能測試主要檢查世紀功能是否符合用戶的需求,所以測試的大部分工做也是圍繞軟件的功能進行。設計軟件的目的就是知足用戶對其功能的需求,若是偏離了這個目的,則任何測試工做都是沒有意義的。

功能測試又能夠細分爲不少種:邏輯功能測試,界面測試、易用性測試、安裝測試、兼容性測試等。

1.3.2 性能測試

  性能測試是經過自動化的測試工具模擬多種正常、峯值以及異常負載條件來對系統的各項性能指標進行的測試。

  軟件的性能包括不少方面,主要有時間性能和空間性能兩種。

  • 時間性能:主要是指軟件的一個具體的響應時間。例如一個登錄所須要的時間,一個商品交易所須要的時間等。固然,拋開具體的測試環境,來分析一次事務的響應時間是沒有任何意義的,它須要在搭建好的一個具體且獨立的測試環境下進行。
  • 空間性能:主要指軟件運行時所消耗的系統資源,例如硬件資源,CPU、內存、網絡寬帶消耗等。

 

1.4 手工測試與自動化測試

從對軟件測試工做的自動化程度能夠劃分爲手工測試與自動化測試。

1.4.1 手工測試

手工測試就是由測試人員一個一個地去執行測試用例,經過鍵盤鼠標等輸入一些參數,並查看返回結果是否符合預期結果。

手工測試並不是專業術語,手工測試一般是指咱們在系統測試階段所進行的功能測試,爲了更明顯地與自動化測試進行區分,這裏使用了手工測試這種說法。

1.4.2 自動化測試

  自動化測試是把以人爲驅動的測試行爲轉化爲機器執行的一種過程。一般,在設計測試用例並經過評審以後,由測試人員根據測試用例中描述的規則流程一步步執行測試,把獲得的世紀結果與指望結果進行比較。在此過程當中,爲了節省人力、時間和硬件資源,提升測試效率,便引入了自動化測試的概念。

自動化測試又可分爲:功能自動化測試與性能自動化測試。

  • 功能自動化測試:是把以人爲驅動的測試行爲轉化爲機器執行的一種過程。經過測試工具(或框架)錄製/編寫測試腳本,對軟件的功能進行測試,並驗證測試結果是否正確,從而代替部分的手工測試工做,達到節約人力成本和時間成本的目的。
  • 性能自動化測試:經過性能功能來模擬成千上萬的虛擬用戶向系統發送請求,從而驗證系統的處理能力。

 

1.5 冒煙測試、迴歸測試、隨機測試、探索性測試和安全測試

這幾種測試出如今軟件測試的週期中,既不算具體明確的測試階段,也不是具體的測試方法。

1.5.1 冒煙測試

  是指在對一個新版本進行大規模的系統測試以前,先驗證一下軟件的基本功能是否實現,是否具有可測性。

  引入到軟件測試中,就是指測試小組在正是測試一個新版本以前,先投入較少的人力和時間驗證一個軟件的主要功能,若是主要功能都沒有運行經過,則打回開發組從新開發。這樣作的好處是能夠節省時間和人力投入到不可測的項目中。

1.5.2 迴歸測試

  迴歸測試是指修改了舊代碼後,從新進行測試以確認修改後沒有引入新的錯誤或致使其餘代碼產生錯誤。
  迴歸測試通常是在進行第二輪軟件測試時開始的,驗證第一輪軟件測試中發現的問題是否獲得修復。固然,迴歸也是一個循環的過程,若是迴歸的問題通不過,則須要開發人員修改後再次進行迴歸,直到全部問題迴歸經過爲止。

1.5.3 隨機測試

  是指測試中的全部輸入數據都是隨機生成的,其目的是模擬用戶的真實操做,並發現一些邊緣性的錯誤。

  隨機測試能夠發現一些隱蔽的錯誤,可是也有不少缺點,例如測試不繫統,沒法統計代碼覆蓋率和需求覆蓋率、發現的問題難以重現等。通常是放在測試的最後執行。隨機測試更專業的升級版叫作探索性測試。

1.5.4 探索性測試

  探索性測試能夠說是一種測試思惟技術,它沒有不少實際的測試方法、技術和工具,但倒是全部測試人員多應該掌握的一種測試思惟方式。探索性測試強調測試人員的主觀能動性,拋棄繁雜的測試計劃和測試用例設計過程,強調在碰到問題時及時改變測試策略。

1.5.5 安全測試

  安全測試在IT軟件產品的生命週期中,特別是產品開發基本完成至發佈階段,對產品進行檢驗以驗證產品符合安全需求定義和產品質量標準的過程。

  安全測試如今愈來愈受到企業的關注和重視,由於因爲安全性問題形成的後果是不可估量的,尤爲是互聯網產品,最容易遭受各類安全攻擊。

 

2、分層的自動化測試

  咱們應該有更多的低級別的單元測試,而不只僅是經過用戶界面運行的高層的端到端的測試。

 

   傳統的自動化測試咱們能夠理解爲基於產品UI層的自動化測試,它是將黑盒功能測試轉化爲由程序或工具執行的一種自動化測試。

   可是在目前的大多數研發組織當中,都存在開發與測試團隊割裂(部門牆)、質量職責錯配(測試主要對質量負責)的問題,在這種狀態下,測試團隊的一個「正常」反應就是試圖在測試團隊可以掌握的黑盒測試環節進行儘量全面的覆蓋,甚至是儘量全面的  UI 自動化測試。

  這可能會致使兩個惡果:一是測試團隊規模的急劇膨脹;二是所謂的全面UI自動化測試運動。由於UI是很是易變得,因此UI自動化測試維護成本相對高昂。

  分層自動化測試倡導的是從黑盒(UI)單層到黑白盒多層的自動化測試體系,從全面黑盒自動化測試到對系統的不一樣層次進行自動化測試。

 

2.1 單元自動化測試

  單元自動化測試是指對軟件中的最小可測試單元進行檢查和驗證。對於單元測試中單元的含義,通常來講,要根據實際狀況去判斷其具體含義,如C語言中單元是指一個函數,Java中單元是指一個類,圖形化的軟件中單元是指一個窗口或一個菜單等。總的來講,單元就是人爲規定的最小的被測功能模塊。規範的進行單元測試須要藉助單元測試框架,如Java語言的Junit、TextNG,C#語言的NUnit,以及Python語言的unittest、pytest等,目前幾乎全部的主流語言都有其相應的單元測試框架。
  Code Review中文翻譯爲代碼評審或diamante審查,是指在軟件開發過程當中,經過對源代碼進行系統性檢查的過程。一般的目的是查找系統缺陷、保證軟件整體質量以及提升開發者自身水平。與Code Review 相關的插件和工具備不少,例如Java語言中基於Eclipse的ReviewClipse和Jupiter、主要針對Python語言的Review Board等。

 

2.2 接口自動化測試

  Web應用的接口自動化測試大致分爲兩類:模塊接口測試Web接口測試

2.2.1 模塊接口測試

  主要測試模塊之間的調用與返回。固然,咱們也能夠將其看作是單元測試的基礎。它主要強調對一個類方法或函數的調用,並對返回結果的驗證,所用到的測試工具與單元自動化測試相同。

 2.2.2 Web接口測試

  Web接口測試又能夠分爲兩類:服務器接口測試和外部接口測試。

  • 服務器接口測試:指測試瀏覽器與服務器的接口。咱們知道Web開發通常分前端和後端,前端開發人員用HTML/CSS/JavaScript等技術,後端開發人員用PHP/Java/C#/Python/Ruby等各類語言。用戶的操做是在前端頁面上,須要後端提供服務器接口,前端經過調用這些接口來獲取須要的數據,經過HTTP協議實現先後端的數據傳遞。
  • 外部接口測試:指調用的接口由第三方系統提供。典型的例子就是第三方登陸,例如新上線的產品爲了免於新用戶註冊帳號的麻煩會提供第三方登陸,納悶用戶在登陸的時候調用的就是第三方登陸的接口,用戶登陸信息的驗證由第三方完成,並返回給當前系統是否驗證經過。

固然,接口測試也有相應的類庫或工具,例如測試HTTP的有HttpUnit、Postman等

 

2.3 UI自動化測試

  UI層是用戶使用該產品的入口,全部功能都經過這一層提供並展現給用戶,因此測試工做大多集中在這一層進行。爲了減輕這一層的測試人力和時間成本,早期的自動化測試工具主要針對該層設計。目前主流的測試工具備UFT、Watie、Robot Framework、Selenium等。

  除UI層所展現的功能外,前端代碼一樣須要進行測試。在前端開發中最主要的莫過於JavaScript腳本語言,而QUnit就是針對JavaScript的一個強大的單元測試框架。

   測試金字塔映射了不一樣測試階段所投入的自動化測試的比例,UI層被放到了塔尖,這也說明UI層應該投入較少的自動化測試。若是系統只關注UI層的自動化測試並非一種明智的作法,由於其很難從本質上保證產品的質量。若是妄圖實現全面的UI層的自動化測試,那麼須要投入大量的人力和時間,然而, 最終得到的收益可能遠低於所投入的成本,由於對於一個系統來說,越接近用戶其越容易變化,爲了適應這種變化就必需要投入更多的成本。

  既然UI層的自動化測試這麼勞民傷財,那麼咱們是否是隻作單元測試與接口測試就能夠了呢?答案是否認的,由於無論什麼樣的產品,最終呈現給用戶的都是UI層的功能,因此產品才須要招聘大量的測試人員進行UI層的功能測試。也正是由於測試人員在UI層投入了大量的時間與精力,因此咱們纔有必要經過自動化的方式幫助測試人員解放部分重複的工做。因此,應該更多的提倡「半自動化」的開展測試工做,把能夠自動化測試的工做交給工具或腳本完成,這樣測試人員就能夠把更多的精力放在更重要的測試工做上,例如探索性測試等。

  至於在金字塔中每一層測試的投入比例則要根據實際的產品特徵來劃分。在《Google測試之道》一書中提到,Google對產品測試類型劃分爲:小測試、中測試和大測試,採用70%(小),20%(中)、10%(大)的比例,大致對應測試金字塔中的Unit、Service和 UI 層。

  在進行自動化測試中最擔憂的是變化,由於變化會直接致使測試用例的運行失敗,因此須要對自動化腳本進行不斷調整。如何控制失敗、下降維護成本是對自動化測試工具及人員能力的挑戰。反過來說,一份永遠都運行經過的自動化測試用例已經失去了它存在的價值。

 

3、什麼樣的項目適合自動化測試

  1. 任務測試明確,不會頻繁變更。
  2. 每日構建後的測試驗證。
  3. 比較頻繁的迴歸測試。
  4. 軟件系統界面穩定,變更少。
  5. 須要在多平臺上運行的相同測試案例、組合遍歷型的測試,大量的重複任務。
  6. 軟件維護週期長。
  7. 項目進度壓力不太大。
  8. 被測軟件系統開發較爲規範,可以保證系統的可測試性。
  9. 具有大量的自動化測試平臺。
  10. 測試人員具有較強的編程能力。

在咱們廣泛的自動化測試經驗中,通常知足如下三個條件就能夠對項目開展自動化測試。

1. 軟件需求變更不頻繁

  自動化測試腳本變化的大小與頻率決定了自動化測試的維護成本。若是軟件需求變更過於頻繁,那麼測試人員就須要根據變更的需求來不斷地更新自動化測試用例,從而適應新的功能。而腳本的維護自己就是一個開發代碼的過程,須要擴展、修改、調試,有時還須要對架構作出調整。若是所花費的維護成本高於利用其節省的測試成本,那麼自動化測試就失去了它的價值與意義。

  一種折中的作法是先對系統中相對穩定的模塊與功能進行自動化測試,而變更較大的部分用用工進行測試。

2. 項目週期較長

  因爲自動化測試需求的肯定,自動化測試框架的設計、腳本的開發與調試均須要時間來完成,而這個過程自己就是一個軟件的開發過程,若是項目的週期較短,沒有足夠的時間去支持這樣一個過程的話,那麼就不須要進行自動化測試了。

3. 自動化測試腳本可重複使用

  自動化測試腳本的重複使用要從三個方面來考量:一是所測試的項目之間是否存在很大的差別性(如C/S系統架構與B/S系統架構的差別);二是所選擇的測試技術和工具是否適應這種差別;三是測試人員是否有能力設計開發出適應這種差別的自動化測試框架。

 

4、自動化測試及工具簡述

   自動化測試的概念有廣義與俠義之分:廣義上來說,全部藉助工具來輔助進行軟件測試的方法均可以稱爲自動化測試;狹義上來說,主要指基於UI層的功能自動化測試。

目前市面上的自動化測試工具很是多,下面幾款是比較常見的自動化測試工具。

1.UTF

  UTF有QTP和ST合併而來,有HP公司開發。它是一個企業級的自動測試工具,提供了強大易用的錄製回放功能,同時兼容對象識別模式與圖像識別模式兩種識別方式,支持B/S與C/S兩種架構的軟件測試,是目前主流的自動化測試工具。

2. Robot Framework

  Robot Framework 是一款基於Python語言編寫的自動化測試框架,具有良好的可擴展性,支持關鍵字驅動,能夠同時測試多種類型的客戶端或者接口,能夠進行分佈式測試。

3. Watir

  Watir是一個基於Web模式的自動化功能測試工具。Watir是一個Ruby語言庫,使用Ruby語言進行腳本開發。

4. Selenium

  Selenium也是一個用於Web應用程序測試的工具,支持多平臺、多瀏覽器、多語言去實現自動化測試。目前在Web自動化領域應用愈來愈普遍。

 

固然,除上面所列的自動化測試工具外,根據不一樣的應用還有不少商業的或開源的以及公司本身開發的自動化測試工具。

 

5、Selenium工具介紹

5.1 什麼是Selenium?

  Selenium主要用於Web應用程序的自動化測試,但並不侷限於此,它還支持全部基於Web的管理任務自動化。

Selenium的特色以下:

  • 開源、免費
  • 多瀏覽器支持:Firefox、Chrome、IE、Opera、Edge
  • 多平臺支持:Linux Windows MAC
  • 多語言支持:Java Python Ruby C# JavaScript C++
  • 對Web頁面有良好的支持
  • 簡單(API簡單),靈活(用開發語言驅動)
  • 支持分佈式測試用例執行

 

5.2 Selenium IDE

  Selenium IDE是嵌入到Firefox瀏覽器中的一個插件,實現簡單的瀏覽器操做的錄製與回放功能。官方定位:

快速地建立bug重現腳本,在測試人員測試過程當中,發現bug以後能夠經過IDE將重現的步驟錄製下來,以幫助開發人員更容易地重現BUG

 IDE錄製的腳本能夠轉換成多種語言,從而幫助咱們快速地開發腳本。關於這個功能在後面的章節中咱們會着重介紹。

 

5.3 Selenium Grid

  Selenium Grid是一種自動化的測試輔助工具,Gird經過利用現有的計算機基礎設施,能加快Web-App的功能測試。利用Grid能夠很方便地實如今多臺機器上和異構環境中運行測試用例

 

5.4 Selenium RC

  Selenium RC是Selenium家族的核心部分。Selenium RC支持多種不一樣語言編寫的自動化測試腳本,經過Selenium RC的服務器做爲代理服務器去訪問應用,從而達到測試的目的。

  Selenium RC分爲Client Libraries和Selenium Server。Client Libraries庫主要用於編寫測試腳本,用來控制Selenium Server的庫。Selenium Server負責控制瀏覽器行爲。總的來講,Selenium Server主要包括三部分,Launcher/Http Proxy和Core。其中,Selenium Core是被Selenium Server 嵌入到瀏覽器頁面中的。其實Selenium Core就是一堆JavaScript函數的集合,即經過這些JavaScript函數,咱們才能夠實現用程序對瀏覽器進行操做。Launcher用於啓動瀏覽器,把Selenium Core加載到瀏覽器頁面當中,並把瀏覽器的代理設置爲Selenium Server的Http Proxy。

 

5.5 Selenium 2.0

  搞清了Selenium 1.0的家族關係,再來看看Selenium 2.0。Selenium 2.0就是把 WevDriver 加入到了這個家族中,簡單用公式表示爲:

Selenium 2.0 = Selenium1.0 + WebDriver

  須要強調的是,在Selenium 2.0中主推的是WebDriver,能夠將其看作Selenium RC 的替代品。由於Selenium爲了保持向下的兼容性,因此在Selenium 2.0中並無完全地拋棄Selenium RC。若是是初次使用Selenium開發一個新的自動化測試項目,那麼能夠直接使用WebDriver。

Selenium RC與WebDriver的區別

  Selenium RC是在瀏覽器中運行JavaScript應用,使用瀏覽器內置的JavaScript翻譯器來翻譯和執行selenese命令(selenese是Selenium命令集合)。

  WebDriver是經過原生瀏覽器支持或者瀏覽器擴展來直接控制瀏覽器。WebDriver針對各個瀏覽器而開發,取代了嵌入到被測Web應用中的JavaScript,與瀏覽器緊密集成,所以支持建立更高級的測試,避免了JavaScript安全模型致使的限制。除了來自瀏覽器廠商的支持以外,WebDriver還利用操做系統級的調用,模擬用戶輸入

Selenium 與 WebDriver 合併緣由?

  部分緣由是WebDriver 解決了Selenium存在的缺點(例如可以繞過JavaScript沙箱,咱們有出色的API)。部分緣由是 Selenium 解決了WebDriver存在的問題(例如支持普遍的瀏覽器),部分緣由是由於Selenium的主要貢獻者和WebDriver的主要貢獻者都以爲合併項目是爲用戶提供最優秀框架的最佳途徑。

WebDriver API

火狐瀏覽器驅動:https://github.com/mozilla/geckodriver/releases

谷歌瀏覽器驅動:http://npm.taobao.org/mirrors/chromedriver

Selenium 及 驅動 安裝

pip install Selenium
下載瀏覽器驅動
http://www.seleniumhq.org/download/
把下載的瀏覽器驅動即相應的exe文件放在PATH下便可。

from selenium import webdriver
import time

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

driver.find_element_by_id("kw").send_keys("Selenium2")
driver.find_element_by_id("su").click()
time.sleep(10)
driver.quit()

1、什麼是Selenium 和WebDriver?

  Selenium是一個瀏覽器自動化操做框架。Selenium主要由三種工具組成。第一個工具SeleniumIDE,是Firefox的擴展插件,支持用戶錄製和回訪測試。錄製/回訪模式存在侷限性,對許多用戶來講並不適合,所以第二個工具——Selenium WebDriver提供了各類語言環境的API來支持更多控制權和編寫符合標準軟件開發實踐的應用程序。最後一個工具——SeleniumGrid幫助工程師使用Selenium API控制分佈在一系列機器上的瀏覽器實例,支持併發運行更多測試。在項目內部,它們分別被稱爲「IDE」、「WebDriver」和「Grid」。

  這裏主要介紹它的第二個工具:WebDriver。

  官網上是這麼介紹它的:WebDriver is a clean, fast framework for automated testing of webapps. 可是我以爲它並不侷限與進行自動化測試,徹底能夠用做其它用途。

  WebDriver針對各個瀏覽器而開發,取代了嵌入到被測Web應用中的JavaScript。與瀏覽器的緊密集成支持建立更高級的測試,避免了JavaScript安全模型致使的限制。除了來自瀏覽器廠商的支持,WebDriver還利用操做系統級的調用模擬用戶輸入。WebDriver支持Firefox(FirefoxDriver)、IE (InternetExplorerDriver)、Opera (OperaDriver)和Chrome (ChromeDriver)。 它還支持Android (AndroidDriver)和iPhone (IPhoneDriver)的移動應用測試。它還包括一個基於HtmlUnit的無界面實現,稱爲HtmlUnitDriver。WebDriver API能夠經過Python、Ruby、Java和C#訪問,支持開發人員使用他們偏心的編程語言來建立測試。

from selenium import webdriver

b = webdriver.Firefox()
b.get("http://www.baidu.com")
b.find_element_by_id("kw").send_keys("火影")
b.find_element_by_id("su").click()
b.close()

在不一樣的編程語言中會有語法的差別,咱們跑去這些差別,在不一樣的語言中實現百度搜索的自動化實例都完成了下面幾個操做。

  1. 首先導入Selenium(WebDriver)相關模塊。
  2. 調用Selenium的瀏覽器驅動,獲取瀏覽器句柄(driver)並啓動瀏覽器。
  3. 經過句柄訪問百度URL。
  4. 經過句柄操做頁面元素(百度輸入框和按鈕)。
  5. 經過句柄關閉瀏覽器。

  因此,webDriver支持多種編程語言,也能夠看做是多種語言都支持WebDriver,惟一的不一樣在於不一樣語言實現的類和方法名的命名差別性。固然,這樣作的好處不言而喻:每一個人均可以根據本身熟悉的語言來使用 WebDriver 編寫自動化測試腳本。

2、WebDriver API

2.1 元素定位

2.1.1 id 定位

find_element_by_id("id")

2.1.2 name 定位

find_element_by_name("name")

2.1.3 class 定位

find_element_by_class_name("class")

2.1.4 tag 定位

find_element_by_tag_name("div")
# 就是標籤,好比<div>/<span>等

2.1.5 link 定位

  link 定位與前面介紹的幾種定位方法有所不一樣,它專門用來定位文本連接。百度輸入框上面的幾個文本連接的代碼以下:

<a class="mnav" name="tj_trnews" href="http://www.baidu.com">新聞</a>
<a class="mnav" name="tj_trhao123" href="http://www.hao123.com">hao123</a>
<a class="mnav" name="tj_trmap" href="http://map.baidu.com">地圖</a>
<a class="mnav" name="tj_trvideo" href="http://v.baidu.com">視頻</a>
<a class="mnav" name="tj_trtieba" href="http://tieba.baidu.com">貼吧</a>

  其實能夠使用name屬性來定位。這裏演示link定位的使用

 

find_element_by_link_text("新聞")
find_element_by_link_text("hao123")
find_element_by_link_text("地圖")
find_element_by_link_text("視頻")
find_element_by_link_text("貼吧")

  find_element_by_link_text("文本") 方法經過元素標籤對之間的文本信息來定位元素。

2.1.6 partial link 定位

  partial link 定位是對 link 定位的一種補充,有些文本連接會比較長,這個時候咱們能夠取文本連接的一部分定位,只要這一部分信息能夠惟一地標識這個連接。

<a class="mnav" name="tj_lang" href="#">一個很長很長的文本連接</a>

  能夠以下定位:

find_element_by_partial_link_text("一個很長的")
find_element_by_partial_link_text("文本連接")

  find_element_by_partial_link_text()方法經過元素標籤對之間的部分文本信息來定位元素。

 

  前面介紹的幾種定位方法相對來講比較簡單,理想狀態下,在一個頁面當中每個元素都有一個惟一id和name屬性值,咱們能夠經過它們的屬性值來找到它們。但在實際項目中並不是想象得這般美好,有時候一個元素並無id、name屬性,或者頁面上多個元素的id和name屬性值相同,又或者每一次刷新頁面,id值都會隨機變化。怎麼辦?能夠用Xpath與CSS定位。

2.1.7 XPath 定位

  可參考:http://www.w3school.com.cn/xpath/index.asp

  XPath是一種在XML文檔中定位元素的語言。由於HTML能夠看作XML的一種實現,因此selenium用戶能夠使用這種強大的語言在web應用中定位元素。

  絕對路徑定位

  XPath 有多種定位策略,最簡單直觀的就是寫出元素的絕對路徑。

  參考baidu.html前端工具所展現的代碼,咱們能夠經過下面的方式找到百度輸入框和搜索按鈕。

find_element_by_xpath("/html/body/div/div[2]/div/div/div/from/span/input")
find_element_by_xpath("/html/body/div/div[2]/div/div/div/from/span[2]/input")

  find_element_by_xpath()方法使用XPath語言來定位元素。XPath主要用標籤名的層級關係來定位元素的絕對路徑,最外層爲html語言。在body文本內,一級一級往下查找,若是一個層級下有多個相同的標籤名,那麼就按上下順序肯定是第幾個,例如,div[2]表示當前層級下的第二個div標籤。

  利用元素屬性定位

  除了使用絕對路徑外,XPath 也能夠使用元素的屬性值來定位。一樣以百度輸入框和搜索按鈕爲例:

find_element_by_xpath("//*[@id='kw']")   #注意外層 " 符號和內層  ' 符號
find_element_by_xpath("//*[@id='su']")

  //表示當前頁面某個目錄下,input 表示定位元素的標籤名,[@id="kw"]表示這個元素的 id 屬性值等於 kw。下面經過name和class屬性值來定位。

  瀏覽器開發者工具F12,複製,XPath

  層級與屬性結合

  若是一個元素自己沒有能夠惟一標識這個元素的屬性值,name咱們能夠找其上一級元素,若是它的上一級元素有能夠惟一標識屬性的值。也能夠拿來使用。

find_element_by_xpath('//[@id="cnblogs_post_body"]/p[1]/a[1]')

  使用邏輯運算符

  若是一個屬性不能惟一地區分一個元素,咱們還能夠使用邏輯運算符連接多個屬性來查找元素。

<input type="text" id="kw" class="su" name="ie">
<input type="text" id="kw" class="aa" name="ie">
<input type="text" id="bb" class="su" name="ie">

  如上面的三行元素,假設咱們如今要定位第一行元素,若是使用 id 將會與第二行元素重名,若是使用 class 將會與第三行元素重名,若是同時使用 id 和 class 就會惟一地標識這個元素,這個時候就能夠經過邏輯運算符 「and」 來鏈接兩個條件。

  固然,咱們也能夠用「and」鏈接更多的屬性來惟一地標識一個元素。

find_element_by_xpath('//input[@id="kw" and @class="su"]/span/input')

2.1.8 CSS 定位

  CSS 是一種語言,它用來描述HTML和XML文檔的表現。CSS使用選擇器來爲頁面元素綁定屬性。這些選擇器能夠被Selenium用做另外的定位策略。

  CSS能夠較爲靈活地選擇空間的任意屬性,通常狀況下定位速度要比XPath快,但對於初學者來講學習起來稍微有點難度。

(1) 經過 class 屬性定位

find_element_by_css_selector(".s_ipt")
find_element_by_css_selector(".bgs_btn")

  find_element_by_css_selector()方法用於CSS語言定位元素,點號(.)表示經過class屬性來定位元素。

(2) 經過 id 屬性定位

find_element_by_css_selector("#kw")
find_element_by_css_selector("#su")

(3) 井號(#)表示經過 id 屬性來定位元素

  經過標籤名定位:

find_element_by_css_selector("input")

  在 CSS 語言中,用標籤名定位元素不須要任何符號標識,直接使用標籤名便可。但咱們前面已經瞭解到,標籤名重複的機率很是大,因此經過這種方式很難找到想要的元素。

(3.1)經過父子關係定位

find_element_by_css_selector("span>input")

  上面的寫法表示有父親元素,它的標籤名爲apan,查找它的全部標籤名叫input的子元素。

(3.2)經過屬性定位

find_element_by_css_selector("[autocomplete=off]")
find_element_by_css_selector("[name='kw']")
find_element_by_css_selector("[type='submit']")

  在 CSS 當中也能夠使用元素的任意屬性,只要這些屬性能夠惟一標識這個元素,對於屬性值來講,可加引號,也能夠不加,但注意和整個字符串的引號進行區分。

(3.3)組合定位

  咱們固然能夠把上面的定位策略組合起來使用,這就大大增強了定位元素的惟一性。

find_element_by_css_selector("span.bgs_ipt_wr>input.s_inpt")
find_element_by_css_selector("span.bgs_btn_wr>input#su")

  有一個父元素,它的標籤名叫 span;它有一個class屬性值叫 bgs_ipt_wr;它有一個子元素,標籤名叫 input,而且這個子元素的 class 屬性值叫 s_ipt。

  瀏覽器開發者工具F12,複製,selector

2.1.9 用 By 定位元素

  針對前面介紹的 8 種定位方法,WebDriver 還提供了另一套寫法,即統一調用 find_element()方法,經過 By 來聲明定位的方法,而且傳入對應定位方法的定位參數,具體以下:

find_element(By.ID,"kw")
find_element(By.NAME,"wd")
find_element(By.CLASS_NAME,"s_ipt")
find_element(By.TAG_NAME,"input")
find_element(By.LINK_TEXT,"新聞")
find_element(By.PARTIAL_LINK_TEXT,"")
find_element(By.XPATH,"//*[@class='bgs_btn']")
find_element(By.CSS_SELECTOR,"span.bgs_btn_wr>input#su")

  find_element()方法只用於定位元素。它須要兩個參數,第一個參數是定位的類型,由By提供;第二個參數是定位的具體方法,在使用By以前須要將By類導入。

from selenium.webdriver.common.by import By

  經過查看 WebDriver 的底層實現代碼發現它們實際上是一回事兒,例如,find_element_by_id()方法的實現。

    def find_elements_by_id(self, id_):
        """
        Finds multiple elements by id.

        :Args:
         - id\_ - The id of the elements to be found.

        :Returns:
         - list of WebElement - a list with elements if any was found.  An
           empty list if not

        :Usage:
            elements = driver.find_elements_by_id('foo')
        """
        return self.find_elements(by=By.ID, value=id_)

2.二、控制瀏覽器

2.2.1 控制瀏覽器窗口大小

from selenium import webdriver

driver = webdriver.Firefox()
driver.get("http://m.mail.10086.cn")

#參數數字爲像素點
print("設置瀏覽器寬480、高800顯示")
driver.set_window_size(480,800)
driver.quit()

  在PC端執行自動化測試腳本大多的狀況下是但願瀏覽器在全屏模式下執行,那麼能夠使用maximize_window()方法使打開的瀏覽器全屏顯示,其用法與set-window_size() 相同,但它不須要參數。

quit和close的區別:https://blog.csdn.net/yangfengjueqi/article/details/84338167

2.2.2 控制瀏覽器後退、前進

  在使用瀏覽器瀏覽網頁時,瀏覽器提供了後退和前進按鈕,能夠方便地在瀏覽過的網頁之間切換,WebDriver 也提供了對應的 back() forward() 方法來模擬後退和前進按鈕,下面經過例子來演示這兩個方法的使用。

from selenium import webdriver

driver = webdriver.Firefox()

#訪問百度首頁
first_url="http://www.baidu.com"
print("now access %s" %(first_url))
driver.get(first_url)

#訪問新聞頁面
second_url="http://news.baidu.com"
print("now access %s" %(second_url))
driver.get(second_url)

#返回(後退)到百度首頁
print("back to %s" %(first_url))
driver.back()

#前進到新聞頁
print("forward to %s" %(second_url))
driver.forward()
driver.quit()

  爲了看清腳本的執行過程,下面每操做一步都經過print() 來打印當前的 URL 地址,執行結果以下:

now access http://www.baidu.com
now access http://news.baidu.com
back to http://www.baidu.com
forward to http://news.baidu.com

2.2.3 模擬瀏覽器刷新

driver.refresh()     #刷新當前頁面

2.3 簡單元素操做

  • clear():                               清除文本
  • send_keys(*value):          模擬按鍵輸入
  • click():                                單擊元素

  clear() 方法用於清除文本輸入框中的內容。例如,登陸框內通常默認會有「帳號」、「密碼」等提示信息,用於引導用戶輸入正確的數據;但若是直接向輸入框中輸入數據,則可能會與輸入框中的提示信息拼接,從而形成輸入信息錯誤。這個時候能夠先使用clear()方法來清除輸入框中的默認提示信息。

  send_keys() 方法模擬鍵盤向輸入框裏輸入內容。如上面的例子中,經過這個方法向用戶名和密碼框中輸入登陸信息。固然,它的做用不只於此,咱們還能夠用它發送鍵盤按鍵,甚至用它來模擬文件上傳。

  click() 方法能夠用來單擊一個元素,前提是它是能夠被單擊的對象,它與 send_keys() 方法是Web頁面操做中最經常使用到的兩個方法。其實 click() 方法不只可用於單擊一個按鈕,它還能單擊任何能夠單擊的文字/圖片連接、複選框、單選框、下拉框等。

from selenium import webdriver

b = webdriver.Chrome()
b.get("https://mail.qq.com/")
b.find_element_by_xpath('//*[@id="u"]').clear()
b.find_element_by_xpath('//*[@id="u"]').send_keys("578389018@qq.com")
b.find_element_by_xpath('//*[@id="p"]').send_keys("*******")
b.find_element_by_xpath('//*[@id="login_button"]').click()

b.quit()

  會報錯,表示找不到元素。

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id="u"]"}

元素找不到有好幾種可能:

2.3.1 Frame/Iframe緣由定位不到元素

  這個是最多見的緣由,首先要理解下frame的實質,frame中其實是嵌入了另外一個頁面,而webdriver每次只能在一個頁面識別,所以須要先定位到相應的frame,對那個頁面裏的元素進行定位。

解決方案:
  若是 iframe有name或id的話,直接使用switch_to.frame("name值")或switch_to.frame("id值")。以下:
from selenium import webdriver

b = webdriver.Chrome()
b.get("https://mail.qq.com/")
b.switch_to.frame('login_frame')  #需先跳轉到iframe框架
b.find_element_by_xpath('//*[@id="u"]').clear()
b.find_element_by_xpath('//*[@id="u"]').send_keys("578389018@qq.com")
b.find_element_by_xpath('//*[@id="p"]').send_keys("********")
b.find_element_by_xpath('//*[@id="login_button"]').click()

b.quit()
若是iframe沒有name或id的話,則能夠經過下面的方式定位:
#先定位到iframe
#再將定位對象傳給switch_to.frame()方法
from selenium import webdriver

b = webdriver.Chrome()
b.get("https://mail.qq.com/")
elementi= b.find_element_by_xpath('//*[@id="login_frame"]')
b.switch_to.frame(elementi)  #需先跳轉到iframe框架
b.find_element_by_xpath('//*[@id="u"]').clear()
b.find_element_by_xpath('//*[@id="u"]').send_keys("578389018@qq.com")
b.find_element_by_xpath('//*[@id="p"]').send_keys("********")
b.find_element_by_xpath('//*[@id="login_button"]').click()

b.quit()
  若是完成操做後,能夠經過 switch_to.parent_content()方法跳出當前一級iframe,或者還能夠經過 switch_to.default_content()方法跳回最外層的頁面。

2.3.2 Xpath描述錯誤緣由

因爲Xpath層級太複雜,容易犯錯。

能夠使用Firefox的firePath,複製xpath路徑。該方式容易由於層級改變而須要從新編寫過xpath路徑,不建議使用,初學者能夠先複製路徑,而後嘗試去修改它。

2.3.3 頁面尚未加載出來,就對頁面上的元素進行的操做

     這種狀況通常說來,能夠設置等待,等待頁面顯示以後再操做,這與人手工操做的原理同樣:
  1. 設置等待時間;缺點是須要設置較長的等待時間,案例多了測試就很慢;
  2. 設置等待頁面的某個元素出現,好比一個文本、一個輸入框均可以,一旦指定的元素出現,就能夠作操做。
  3. 在調試的過程當中能夠把頁面的html代碼打印出來,以便分析。
解決方案:
導入時間模塊。
import time
time.sleep(3)

2.3.4 動態id定位不到元素

解決方案:
若是發現是動態id,直接用xpath定位或其餘方式定位。

2.3.5 二次定位,如彈出框登陸

     如百度登陸彈出框登陸百度帳號,需先定位到百度彈出框,而後再定位到用戶名密碼登陸。

2.3.6 不可見元素定位

     如上百度登陸代碼,經過名稱爲tj_login查找的登陸元素,有些是不可見的,因此加一個循環判斷,找到可見元素(is_displayed())點擊登陸便可。

參考:http://www.javashuo.com/article/p-pjkfmibd-cn.html

2.3.7 WebElement 接口經常使用方法

submit()

submit() 方法用於提交表單。例如,在搜索框輸入關鍵字以後的「回車」操做,就能夠經過submit() 方法模擬。

from selenium import webdriver

driver = webdriver.Firefox()

driver.get("http://www.youdao.com")

driver.find_element_by_id("translateContent").send_keys("hello")
#提交輸入框的內容
driver.find_element_by_id("translateContent").submit()

  上面的例子,咱們經過定位有道搜索框並經過submit()提交搜索框的內容,一樣達到單擊「搜索」按鈕的效果。有時候 submit() 能夠與 click() 方法互換來使用, submit() 一樣能夠提交一個按鈕,但 submit() 的應用範圍遠不及 click() 普遍。

  • size:                                            返回元素的尺寸
  • text:                                            獲取元素的文本
  • get_attribute(name):                獲取屬性值
  • is_dispalyed():                          設置該元素是否用戶可見,注意,是不可見,不是不存在

 

from selenium import webdriver

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

# 獲取輸入框的尺寸
size = driver.find_element_by_id("kw").size
print(size)

# 返回百度頁面底部備案信息
text = driver.find_element_by_id("cp").text
print(text)

# 返回元素的屬性值,能夠是id、name、type或其餘任意屬性
attribute = driver.find_element_by_id("kw").get_attribute("type")
print(attribute)

# 返回元素的結果是否可見,返回結果爲True或False
result = driver.find_element_by_id("kw").is_displayed()       # 注意,是不可見,不是不存在。不存在會直接報錯
print(result)

driver.quit()

>>>
{'height': 22.0, 'width': 500.0}
©2018 Baidu 使用百度前必讀 意見反饋 京ICP證030173號  京公網安備11000002000001號 
text
True

***Repl Closed***

 2.4 鼠標事件

  ActionChains 類提供了鼠標操做的經常使用方法:

  • perform():                              執行全部ActionChains中存儲的行爲
  • context_click():                     右擊
  • double_click():                      雙擊
  • drag_and_drop():                 拖動
  • move_to_element():            鼠標懸停

2.4.1 鼠標右擊操做

from selenium import webdriver
# 引入 ActionChains 類
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

# 定位到要右擊的元素
right_click = driver.find_element_by_id("kw")
# 對定位到的元素執行鼠標右鍵操做
ActionChains(driver).context_click(right_click).perform()

 

  • from selenium.webdriver.common.action_chains import ActionChains 導入提供鼠標操做的 ActionChains 類
  • ActionChains(driver) 調用 ActionChains() 類,將瀏覽器驅動 driver 做爲參數傳入
  • context_click(right_click)    context_click() 方法用於模擬鼠標右鍵操做,在調用時須要指定元素定位。
  • perform()    執行全部 ActionChains 中儲存的行爲,能夠理解成是對整個操做的提交動做。 

 

2.4.2 鼠標懸停

from selenium import webdriver
# 引入 ActionChains 類
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

# 定位到要懸停的元素
above = driver.find_element_by_id("su")
# 對定位到的元素執行懸停操做
ActionChains(driver).move_to_element(above).perform()

2.4.3 鼠標雙擊操做

from selenium import webdriver
# 引入 ActionChains 類
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

# 定位到要雙擊的元素
double_click = driver.find_element_by_id("su")
# 對定位到的元素執行雙擊操做
ActionChains(driver).double_click(double_click).perform()

2.4.4 鼠標拖動操做

  drag_and_drop(source,target)在源元素上按住鼠標左鍵,而後移動到目標元素上釋放。

  • source:鼠標拖動的源元素
  • target:鼠標釋放的目標元素
from selenium import webdriver
# 引入 ActionChains 類
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

# 定位元素的原位置
element = driver.find_element_by_id("su")
target = driver.find_element_by_id("su")

# 執行元素的拖動操做
ActionChains(driver).drag_and_drop(element,target).perform()

2.5 鍵盤事件

  keys() 類提供了鍵盤上幾乎全部按鍵的方法。前面瞭解到,send_keys()方法能夠用來模擬鍵盤輸入,除此以外,咱們還能夠用它來輸入鍵盤上的按鍵,甚至是組合鍵,如 Ctrl + A ,Ctrl + C等。

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "Q1mi"
# Date: 2018/7/2

from selenium import  webdriver
# 引入Keys模塊
from selenium.webdriver.common.keys import Keys

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

# 輸入框輸入內容
driver.find_element_by_id("kw").send_keys("seleniumm")

# 刪除多輸入的一個m
driver.find_element_by_id("kw").send_keys(Keys.BACK_SPACE)

# 輸入空格鍵 + 「教程」
driver.find_element_by_id("kw").send_keys(Keys.SPACE)
driver.find_element_by_id("kw").send_keys("教程")

# ctrl + a 全選輸入框內容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,"a")

# ctrl + x 剪切輸入框內容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,"x")

# ctrl + v 粘貼內容到輸入框
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,"v")

# 經過回車鍵來代替單擊操做
driver.find_element_by_id("su").send_keys(Keys.ENTER)

  如下爲經常使用的鍵盤操做:

send_keys(Keys.BACK_SPACE)       刪除鍵(BackSpace)
send_keys(Keys.SPACE)            空格鍵(Space)
send_keys(Keys.TAB)              製表鍵(Tab)
send_keys(Keys.ESCAPE)           回退鍵(Esc)
send_keys(Keys.ENTER)            回車鍵(Enter)
send_keys(Keys.CONTROL,"a")      全選(Ctrl+A)
send_keys(Keys.CONTROL,"c")      複製(Ctrl+C)
send_keys(Keys.CONTROL,"x")      剪切(Ctrl+X)
send_keys(Keys.CONTROL,"v")      粘貼(Ctrl+V)
send_keys(Keys.F1)               鍵盤F1
......                           .
send_keys(Keys.F12)              鍵盤F12

2.6 獲取驗證信息

  在編寫功能測試用例時,會假定一個預期結果,在執行用例的過程當中把獲得的實際結果與預期結果進行比較,從而判斷用戶的經過或失敗。自動化測試用例是由機器去執行的,一般機器並不像人同樣有思惟和判斷能力,那麼是否是模擬各類操做頁面的動做沒有報錯就說明用例執行成功呢?並不是如此,假如咱們模擬百度搜索的用例,當新的迭代版本上線後,每一頁的搜索結果少一條,但用例的執行不會報錯,所以這個 bug 永遠不會被自動化測試發現。

  那麼是否是在運行自動化測試用例時須要由測試人員盯着用例的執行來辨別執行結果呢?若是是這樣的話,自動化測試就失去了「自動化」的意義。在自動化用例執行完成以後,咱們能夠從頁面上獲取一些信息來「證實「用例執行是成功仍是失敗。

  一般用得最多的幾種驗證信息分別是title、URL和text。text方法在前面已經講過,它用於獲取標籤對之間的文本信息。

from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.get("https://mail.qq.com/")
time.sleep(2)
frame_add = driver.find_element_by_xpath('//*[@id="login_frame"]')
driver.switch_to_frame(frame_add)  #需先跳轉到iframe框架
print("Before login==========")

# 打印當前頁面title
now_title = driver.title print(now_title)


# 打印當前頁面URL
now_url = driver.current_url print(now_url)

# 執行郵箱登陸
driver.find_element_by_id("u").clear()
driver.find_element_by_id("u").send_keys("578389018@qq.com")
driver.find_element_by_id("p").clear()
driver.find_element_by_id("p").send_keys("*******")
driver.find_element_by_id("login_button").click()
time.sleep(5)

print("After login==========")
# 再次打印當前頁面title
now_title = driver.title
print(now_title)


# 再次打印當前頁面URL
now_url = driver.current_url
print(now_url)

# 獲取登陸的用戶名
user = driver.find_element_by_id("useraddr").text print(user)

driver.quit()

>>>
C:\Users\Administrator\AppData\Local\Programs\Python\Python37\python.exe C:/Users/Administrator/Desktop/py/test.py
Before login==========
登陸QQ郵箱
https://mail.qq.com/
After login==========
QQ郵箱
https://mail.qq.com/cgi-bin/frame_html?sid=IDp2I6d3Vi8WORtA&r=b6242c8e186a9f7c4b80aab437e760f8
dongye95@foxmail.com

Process finished with exit code 0
  • title:用於得到當前頁面的標題。
  • current_url:用戶得到當前頁面的URL

  經過打印結果,咱們發現登陸先後的title和URL明顯不一樣。咱們能夠把登陸以後的這些信息存放起來,做爲登陸是否成功的驗證信息。固然,這裏URL每次登陸都會有所變化,是不能拿來作驗證信息的。title能夠拿來作驗證信息,但它並不能明確地標識是哪一個用戶登陸成功了,所以經過text獲取用戶文本(dongye95@foxmail.com)是很好的驗證信息。

 

 2.7 設置元素等待

  現在大多數Web應用程序使用AJAX技術。當瀏覽器在加載頁面時,頁面上的元素可能並非同時被加載完成的,這給元素的定位增長了困難。若是由於在加載某個元素時延遲而形成ElementNotVisibleException的狀況出現,那麼就會下降自動化腳本的穩定性,咱們能夠經過設置元素等待改善這種問題形成的不穩定。

  WebDriver提供了兩種類型的等待:顯式待和隱式等待

2.7.1 顯式等待

    顯式等待使 WebDriver 等待某個條件成立時繼續執行,不然在達到最大時長時拋棄超時等待。(TimeoutException)

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

element = WebDriverWait(driver, 5, 0.5).until(
    EC.presence_of_element_located((By.ID,"kw"))
    )

element.send_keys('selenium')
driver.quit()

  WebDriverWait 類是由 WebDriver 提供的的等待方法。在設置時間內,默認每隔一段時間檢測一次當前頁面元素是否存在,若是超過設置時間檢測不到則拋出異常。具體格式以下

WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
  • driver                                瀏覽器驅動
  • timeout                             最長超時時間,默認以秒爲單位
  • poll_frequency                 檢測的間隔(步長)時間,默認爲0.5s    
  • ignored_exceptions         超時後的異常信息,默認狀況下拋NoSuchElementException 異常

  WebDriverWait() 通常由 until() 或者 until_not() 方法配合使用,下面是 until() 和 until_not() 方法的說明。

  • until(method, message=' ')

  調用該方法提供的驅動程序做爲一個參數,直到返回值爲True

  • until_not(method, message=' ')

  調用該方法提供的驅動程序做爲一個參數,直到返回值爲False

  在本例中,經過 as 關鍵字將 expected_conditions 重命名爲 EC,並調用 presence_of_element_located() 方法判斷元素是否存在。

  expected_conditions 類所提供的預期條件判斷的方法以下表所示。

  除expected_conditions 所提供的豐富的預期條件判斷方法外,還能夠使用前面學過的is_displayed() 方法來判斷元素是否可見。

from selenium import webdriver
from time import sleep, ctime

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

print(ctime())
for i in range(10):
    try:
        el = driver.find_element_by_id("kw22")
        if el.is_displayed():
            break
    except Exception as e:
        pass
        sleep(1)
else:
    print("time out")
driver.close()
print(ctime())

>>>
Tue Jul  3 09:41:42 2018
time out
Tue Jul  3 09:41:54 2018

***Repl Closed***

  相對來講,這種方式更容易理解,經過for循環10次,每次循環判斷元素的is_displayed()狀態是否爲True;若是爲True,則break跳出循環;不然sleep(1) 後繼續循環判斷,直到10次循環結束後,打印「time out」信息。

2.7.2 隱式等待

  隱式等待是經過必定的時長等待頁面上某元素加載完成。若是超出尚未被加載,則拋出 NoSuchElementException 異常。WebDriver提供方法來實現隱式等待,默認設置爲0.它的用法相對來講要簡單得多。

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from time import ctime

driver  = webdriver.Firefox()

# 設置隱式等待10秒
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")

try:
    print(ctime())
    driver.find_element_by_id("kw22").send_keys('selenium')
except NoSuchElementException as e:
    print("查找元素異常 %s" %(e))
else:
    pass
finally:
    print(ctime())
    driver.quit()

>>>
Wed Jul  4 12:51:30 2018
查找元素異常 Message: Unable to locate element: [id="kw22"]

Wed Jul  4 12:51:40 2018

Process finished with exit code 0

  implicitly_wait() 默認參數的單位爲秒,本例中設置等待時長爲10秒。首先這10秒並不是一個固定的等待時間,它並不影響腳本的執行速度。其次,它並不針對頁面上的某一元素進行等待。當腳本執行到某個元素定位時,若是元素能夠定位,則繼續執行;若是元素定位不到,則它將以輪詢的方式不斷地判斷元素是否被定位到。假設在第6秒定位到了元素則繼續執行,若直到超出設置時間(10秒)尚未定位到元素,則拋出異常。

  在上面的例子中,顯然百度輸入框的定位 id=kw22 是有誤的,經過打印的兩個時間能夠看出,當執行度一百度輸入框的操做時,超過了10秒的等待。

2.7.3 sleep 休眠方法

  有時候咱們但願腳本在執行到某一位置時作固定時間的休眠,尤爲是在腳本調試過程當中。這時能夠使用sleep()方法,須要說明的是,sleep()方法由Python的time模塊提供。

from selenium import webdriver
from time import sleep

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

sleep(2)
driver.find_element_by_id("kw").send_keys("webdriver")
driver.find_element_by_id("su").click()
sleep(3)

driver.quit()

  當執行到sleep()方法時會固定休眠必定的時長,而後再繼續執行。sleep()方法默認參數以秒爲單位,若是設置時長小於1秒,則能夠用小數表示,如sleep(0.5)表示休眠0.5秒。

 

2.8 定位一組元素

  在2.4中咱們已經學了8中定位方法,這8種定位方法時針對單個元素定位的,WebDriver還提供了與之對應的8種用於定位一組元素的方法。

find_elements_by_id()
find_elements_by_name()
find_elements_by_class_name()
find_elements_by_tag_name()
find_elements_by_link_text()
find_elements_by_partial_link_text()
find_elements_by_xpath
find_elements_by_css_selector()

  定位一組元素的方法與定位單個元素的方法相似,惟一的區別是在單詞element後面多了一個s表示複數。定位一組元素通常用於如下場景:

  • 批量操做元素,例如勾選頁面上全部的複選框
  • 先獲取一組元素,再從這組對象中過濾出須要操做的元素。例如定位出頁面上全部的checkbox而後選擇其中的一個進行操做。
from selenium import webdriver
import os,time

driver = webdriver.Firefox()
file_path = "file:///" + os.path.abspath("checkbox.html")   # file:/// 換成 file: 也能夠,可是這個是必須的前綴
driver.get(file_path)

# 選擇頁面上全部的tag name 爲input的元素
inputs = driver.find_elements_by_tag_name('input')

# 而後從中過濾出type爲checkbox的元素,單擊勾選
for i in inputs:
    if i.get_attribute("type") == "checkbox":
        i.click()
        time.sleep(1)

driver.quit()

  前面提到,經過tag name的定位方式很難定位到單個元素,由於元素標籤名重名的機率很高,於是在定位一組元素時,這種方式就派上用場了。在上面的例子中先經過find_elements_by_tag_name()找到一組標籤名爲input的元素。而後經過for循環進行遍歷,在遍歷過程當中,經過get_attribute()方法獲取元素的type屬性是否爲「checkbox」,若是爲「checkbox」,就認爲這個元素是一個複選框,對其進行勾選操做。

  須要注意的是,在上面的例子中,經過瀏覽器打開的是一個本地的html文件,因此須要用到Python的os模塊,path.abspath()方法用於獲取當前路徑下的文件。

  除此以外,咱們還能夠使用XPath或CSS來直接判斷屬性值,從而進行單擊操做。

from selenium import webdriver
import os,time

driver = webdriver.Firefox()
file_path = "file:///" + os.path.abspath("checkbox.html")
driver.get(file_path)

# 經過XPath找到type=checkbox的元素
# checkboxes = driver.find_elements_by_xpath("//input[@type='checkbox']")

# 經過CSS找到type=checkbox的元素
checkboxes = driver.find_elements_by_css_selector("//input[type=checkbox]")
for checkbox in checkboxes:
    if i.get_attribute("type") == "checkbox":
        checkbox.click()
        time.sleep(1)

# 打印當前頁面上的type爲checkbox的個數
print(len(checkboxes))

# 把頁面上最後1個checkbox的鉤給去掉
driver.find_element_by_css_selector("input[type=checkbox]").pop().click()

driver.quit()

  經過XPath或CSS來查找一組元素時,省去了判斷步驟。由於定位方法已經作了判斷,只需循環對這一組元素進行勾選便可。

 

2.9 多表單切換

  在Web應用中常常會遇到frame/iframe表單嵌套頁面的應用,WebDriver只能在一個頁面上對元素識別與定位,對於frame/iframe表單內嵌頁面上的元素沒法直接定位。這時就須要經過switch_to.frame() 方法將當前定位的主體切換爲frame/iframe表單的內嵌頁面中。

from selenium import webdriver

b = webdriver.Chrome()
b.get("https://mail.qq.com/")

# 切換到  iframe(id="login_frame")
b.switch_to.frame('login_frame')
  
b.find_element_by_xpath('//*[@id="u"]').clear()
b.find_element_by_xpath('//*[@id="u"]').send_keys("578389018@qq.com")
b.find_element_by_xpath('//*[@id="p"]').send_keys("********")
b.find_element_by_xpath('//*[@id="login_button"]').click()

b.quit()

  switch_to.frame() 默承認以直接取表單的 id 或 name 屬性。若是 iframe 沒有可用的 id 和 name 屬性,則能夠經過下面的方式進行定位。

from selenium import webdriver

b = webdriver.Chrome()
b.get("https://mail.qq.com/")

# 先經過xpath定位到iframe
elementi= b.find_element_by_xpath('//*[@id="login_frame"]')
#再將定位對象傳給switch_to.frame()方法
b.switch_to.frame(elementi)

b.find_element_by_xpath('//*[@id="u"]').clear()
b.find_element_by_xpath('//*[@id="u"]').send_keys("578389018@qq.com")
b.find_element_by_xpath('//*[@id="p"]').send_keys("********")
b.find_element_by_xpath('//*[@id="login_button"]').click()
b.switch_to.parent_frame()
b.quit()

 switch_to包的方法詳解

  在switch_to的基礎上,有這麼幾個方法,鑑於基本上都是以前曾經講過的,此次把等價的方法也列出來,供你們參考

1. driver.switch_to.active_element() ---------------替換-------------- driver.switch_to_active_element()

  定位到當前聚焦的元素上      聚焦這部分參考:https://blog.csdn.net/huilan_same/article/details/52338073

2. driver.switch_to.alert() ---------------替換--------------  driver.switch_to_alert()

  切換到alert彈窗

3. driver.switch_to.default_content() ---------------替換-------------- driver.switch_to_default_content()

  切換到最上層頁面

4. driver.switch_to.frame(frame_reference) ---------------替換--------------driver.switch_to_frame(frame_reference)

  經過id、name、element(定位的某個元素)、索引來切換到某個frame

5. driver.switch_to.parent_frame()

  這是switch_to中獨有的方法,能夠切換到上一層的frame,對於層層嵌套的frame頗有用

6. driver.switch_to.window(window_name)           等同於     driver.switch_to_window(window_name)

  切換到制定的window_name頁面

  注: 官方把selenium.webdriver包中的switch方法所有封裝成了一個包,這樣可以比較明瞭和方便,也符合軟件編程中的高內聚低耦合的思想。

 

2.10 多窗口切換

   在頁面操做過程當中有時候點擊某個連接會彈出新的窗口,這時就須要主機切換到新打開的窗口上進行操做。WebDriver提供了switch_to.window() 方法,能夠實如今不一樣的窗口之間切換。

  以百度首頁和百度註冊頁爲例。

from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")

# 得到百度搜索窗口句柄
sreach_windows = driver.current_window_handle

driver.find_element_by_link_text("登陸").click()
driver.find_element_by_link_text("當即註冊").click()

# 得到當前全部打開的窗口的句柄
all_handles = driver.window_handles

# 進入註冊窗口
for handle in all_handles:
    if handle != sreach_windows:
        driver.switch_to.window(handle)
        print("now register window!")
        driver.find_element_by_name("userName").send_keys("username")
        driver.find_element_by_id("TANGRAM__PSP_3__password").send_keys("password")
        time.sleep(2)

# 回到搜索窗口
for handle in all_handles:
    if handle == sreach_windows:
        driver.switch_to.window(handle)
        print("now sreach window!")

        # 會跳出來一個讓你下載APP的彈窗,把這個彈窗給點掉
        try:
            driver.find_element_by_id("TANGRAM__PSP_4__closeBtn")
        except:
            break
        else:
            driver.find_element_by_id("TANGRAM__PSP_4__closeBtn").click()

        # 彈窗消失後,再去查找
        driver.find_element_by_id("kw").send_keys("selenium")
        driver.find_element_by_id("su").click()
        time.sleep(2)

driver.quit()

 

  腳本的執行過程:首先打開百度首頁,經過current_window_handle 得到當前窗口的句柄,並賦值給變量sreach_handle。接着打開登陸彈窗,在登陸彈窗上單擊「當即註冊」,從而打開新的註冊窗口。經過window_handles得到當前打開的全部窗口的句柄,並賦值給變量all_handles。

  第一個循環遍歷all_handles,若是handle不等於sreach_handle,那麼必定是註冊窗口,由於腳本執行過程當中只打開了兩個窗口。因此,經過switch_to.window()切換到註冊頁進行註冊操做。第二個循環相似,不過這一次判斷若是handle等於sreach_handle,那麼切換到百度搜索頁,而後進行搜索操做。

  在本例中所涉及的新方法以下:

  current_window_handle:得到當前窗口句柄。

  window_handles:返回全部窗口的句柄到當前會話。

  switch_to.window():用於切換到相應的窗口,與上一節的switch_to.frame()相似,前者用於不一樣窗口的切換,後者用於不一樣表單之間的切換。

 

 2.11 警告框處理

  在WebDriver 中處理JavaScript所生成的alert、confirm以及prompt十分簡單,具體作法是使用switch_to.alert() 方法定位到 alert/confirm/prompt,而後使用text/accept/dismiss/send_keys等方法進行操做。

  • text:返回 alert/confirm/prompt中的文字信息。
  • accept():接受現有警告框
  • dismiss():解散現有警告框
  • send_keys(keysToSend):發送文本至警告框。keysToSend:將文本發送至警告框。

  百度搜索設置彈出的窗口是不能經過前端工具對其進行定位的,這個時候就能夠經過switch_to.alert()方法接受這個彈窗

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time

driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")

# 鼠標懸停至「設置」連接
link = driver.find_element_by_link_text("設置")
ActionChains(driver).move_to_element(link).perform()

# 打開搜索設置
driver.find_element_by_link_text("搜索設置").click()
time.sleep(0.3)   #  沒有這個延遲會出現問題,表如今點不到保存設置上,具體還不清楚咋回事情

# 保存設置
driver.find_element_by_link_text('保存設置').click()


# 接受警告框
driver.switch_to.alert.accept()

driver.quit()

2.12 上傳文件

  上傳文件是比較常見的Web功能之一,但WebDriver並無提供專門用於上傳的方法,如何實現上傳操做關鍵在於上傳文件的思路。

  通常Web頁面的上傳功能的操做須要單擊「上傳」按鈕後打開本地的Window窗口,從窗口中選擇本地文件進行上傳。而webDriver是沒法操做Windows控件,因此,對於初學者來講,通常思路會卡在如何識別Window空間這個問題上。

  對於Web頁面的上傳功能實現通常由如下兩種方式。

  • 普通上傳:普通的附件上傳是將本地文件的路徑做爲一個值放在input標籤中,經過form表單將這個值提交給服務器。
  • 插件上傳:通常是指基於Flash、JavaScript或Ajax等技術所實現的上傳功能。

2.12.1 send_keys 實現上傳

  對於經過input標籤實現的上傳功能,能夠將其看作是一個輸入框,即經過send_keys()指定本地文件路徑的方式實現文件上傳。

from selenium import webdriver
import os,time

driver = webdriver.Chrome()
file_path = "file:///" + os.path.abspath("test.html")
driver.get(file_path)

# 定位上傳按鈕,添加本地文件
driver.find_element_by_name("file").send_keys("C:\\Users\\Administrator\\Desktop\\py\\geckodriver.log")

driver.quit()

2.12.2 Autolt 實現上傳

  autoit 目前最新版本是v3,它是一個使用相似BASIC腳本語言的免費軟件,它被設計用來進行Windows GUI(圖形用戶界面)的自動化測試。它利用模擬鍵盤按鍵,鼠標移動和窗口/控件的組合來實現自動化任務。

  具體參考《自動化測試實戰  基於PYTHON語言》一書4.12.2章節。並不推薦,由於經過Python調用的exe程序並不在Python的可控範圍內。換句話說,exe執行多長時間,執行是否出錯,Python程序都沒法得知。

  pyautoit瞭解一下

  PyAutoGUI 也瞭解一下

 

 

2.13 下載文件

  https://blog.csdn.net/huilan_same/article/details/52789954

  WebDriver 容許咱們設置默認的文件下載路徑,也就是說,文件會自動下載而且存放到設置的目錄中。下面以Firefox瀏覽器爲例,執行文件的下載。

from selenium import webdriver
import os

fp = webdriver.FirefoxProfile()

fp.set_preference("browser.download.folderList",2)
fp.set_preference("browser.download.manager.showWhenStarting",False)
fp.set_preference("browser.download.manager.dir",os.getcwd())
fp.set_preference("browser.helperApps.neverAsk.saveToDisk","application/octet-stream")  # 下載文件的類型

driver = webdriver.Firefox(firefox_profile=fp)
driver.get("http://pypi.Python.org/pypi/selenium")
driver.find_element_by_partial_link_text("selenium-2").click()

  爲了讓Firefox瀏覽器能實現文件下載,咱們須要經過FirefoxProfile()對其作一些設置。

browser.download.folderList

設置成0表明下載到瀏覽器默認下載路徑,設置成2則能夠保存到制定目錄

browser.download.manager.showWhenStarting

是否顯示開始:True爲顯示,Flase爲不顯示

browser.download.dir

用於指定所下載文件的目錄。os.getcwd()函數不須要傳遞參數,用於返回當前的目錄。

browser.helperApps.neverAsk.saveToDisk
指定要下載頁面的Content_type值,「application/octet-stream」爲文件的類型

HTTP Content_type經常使用對照表:http://tool.oschina.net/commons

這些參數的設置能夠經過在Firefox瀏覽器地址欄輸入:about:config進行設置。

  將全部設置信息在調用WebDriver的Firefox()方法時做爲參數傳遞給瀏覽器。Firefox瀏覽器在下載時就根據這些設置信息將文件下載在當前腳本的目錄下。

  上面例子中的設置只針對Firefox瀏覽器,不一樣瀏覽器設置方法不該。通用的藉助 AutoIt來操做Windows空間進行下載。

2.14 操做Cookie

  有時候咱們須要驗證瀏覽器中cookie是否正確,由於基於真實cookie的測試是沒法經過白盒和集成測試的。WebDriver提供了操做Cookie的相關方法,能夠獲取、添加和刪除cookie信息。

  WebDriver 操做 cookie的方法:

  • get_cookies():                                   得到全部cookie信息
  • get_cookie(name):                            返回字典的key爲「name」的cookie信息
  • add_cookie(cookie_dict):                  添加cookie。「cookie_dict」指字典對象,必須有name和value值
  • delete_cookie(name,optionsString):  刪除cookie信息。「name」是要刪除的cookie的名稱,「optionString」是該cookie的選項,目前支持的選項包括「路徑」,「域」。
  • delete_all_cookies():                         刪除全部cookie信息

下面經過get-cookies()來獲取當前瀏覽器的cookie信息

from selenium import webdriver

driver = webdriver.Firefox()
driver.get("http://www.youdao.com")

# 獲取cookie信息
cookie = driver.get_cookies()

# 將得到cookie的信息打印
print(cookie)

driver.quit()

>>>
[{'name': 'YOUDAO_MOBILE_ACCESS_TYPE', 'value': '1', 'path': '/', 'domain': '.youdao.com', 'expiry': 1562137504, 'secure': False, 'httpOnly': False}, {'name': 'DICT_UGC', 'value': 'be3af0da19b5c5e6aa4e17bd8d90b28a|', 'path': '/', 'domain': '.youdao.com', 'expiry': None, 'secure': False, 'httpOnly': False}, {'name': 'OUTFOX_SEARCH_USER_ID', 'value': '-1243283229@60.12.215.75', 'path': '/', 'domain': '.youdao.com', 'expiry': 2476681504, 'secure': False, 'httpOnly': False}, {'name': 'JSESSIONID', 'value': 'abcXbMI_bHumq7K2x9Erw', 'path': '/', 'domain': '.youdao.com', 'expiry': None, 'secure': False, 'httpOnly': False}, {'name': '___rl__test__cookies', 'value': '1530601505713', 'path': '/', 'domain': 'www.youdao.com', 'expiry': None, 'secure': False, 'httpOnly': False}, {'name': 'OUTFOX_SEARCH_USER_ID_NCOO', 'value': '1523083508.1908145', 'path': '/', 'domain': '.youdao.com', 'expiry': 1593673505, 'secure': False, 'httpOnly': False}]

  從執行結果能夠看出,cookie數據是以字典的形式進行存放的。知道了cookie的存放形式,接下來咱們就能夠按照這種形式向瀏覽器中寫入cookie信息。

from selenium import webdriver

driver = webdriver.Firefox()
driver.get("http://www.youdao.com")

# 向cookie的name和value中添加會話信息
driver.add_cookie({"name":"key-aaaa","value":"value-bbbb"})

# 遍歷cookies中的name和value信息並打印,固然還有上面添加的信息。
for cookie in driver.get_cookies():
    print("%s -> %s" %(cookie["name"],cookie["value"]))


driver.quit()

>>>
YOUDAO_MOBILE_ACCESS_TYPE -> 1
DICT_UGC -> be3af0da19b5c5e6aa4e17bd8d90b28a|
OUTFOX_SEARCH_USER_ID -> 871140950@60.12.215.75
JSESSIONID -> abcq80IlD53H4bj3V_Erw
___rl__test__cookies -> 1530601866047
OUTFOX_SEARCH_USER_ID_NCOO -> 2091021681.247173
key-aaaa -> value-bbbb

  從執行結果能夠看到,最後一條cookie信息是在腳本執行過程當中經過 add_cookie() 方法添加的。經過遍歷獲得全部的cookie信息,從而找到key爲「name」和「value」的特定cookie的value。

  那麼在什麼狀況下會用到cookie的操做呢?例如開發人員開發一個功能,當用戶登陸後,會將用戶的用戶名寫入瀏覽器cookie,指定的key爲「username」,那麼咱們就能夠經過 get_cookies()找到username,打印value。若是找不到username或對應的value爲空,那麼說明cookie沒有成功地保存到瀏覽器中。

  delete_cookie()和delete_all_cookies() 的使用也很簡單,前者經過name刪除一個特定的cookie信息,後者直接刪除瀏覽器中的全部cookies()信息。

 

2.15 調用JavaScript

  雖然WebDriver提供了操做瀏覽器的前進和後退方法,但對於瀏覽器滾動條並無提供相應的操做方法。在這種狀況下,就能夠藉助JavaScript來控制瀏覽器的滾動條。WebDriver提供了 execute_script() 方法來執行JavaScript代碼。

  通常咱們想到的必須使用滾動條的場景是:註冊時的法律條文的閱讀。判斷用戶是否閱讀完的標準是,滾動條是否拉到頁面底部。固然,有時候爲了使操做更接近用戶行爲也會使用滾動條,例如用戶要操做的元素在頁面的第二屏,通常用戶不會對看不到的元素進行操做,那麼就須要先將滾動條拖到頁面的第二屏再進行操做。

  用於調整瀏覽器滾動條位置的JavaScript代碼以下:

......
<!-- window.scrollTo(左邊距,上邊距);-->
window.scrollTo(0,450)
......

  window.scrollTo() 方法用於設置瀏覽器窗口滾動條的水平和垂直位置。方法的第一個參數表示水平的左間距,第二個參數表示垂直的上邊距。其代碼以下:

from selenium import webdriver
from time import sleep

# 訪問百度
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

# 設置瀏覽器窗口大小
driver.set_window_size(600,600)

# 搜索
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
sleep(2)

# 經過javascript設置瀏覽器窗口的滾動條位置
js="window.scrollTo(100,450);" driver.execute_script(js)
sleep(3)

driver.quit()

  經過瀏覽器打開百度進行搜索,而且提早經過 set_window_size() 方法將瀏覽器窗口設置爲固定寬高顯示,目的是讓窗口出現水平和垂直滾動條。而後經過 execute_script() 方法執行 JavaScript 代碼來移動滾動條的位置。

 

一、滾動條回到頂部:

js="var q=document.getElementById('id').scrollTop=0"
driver.execute_script(js)

或者

js="var q=document.documentElement.scrollTop=0"
driver.execute_script(js)

二、滾動條拉到底部:

js="var q=document.getElementById('id').scrollTop=10000"
driver.execute_script(js)

或者

js="var q=document.documentElement.scrollTop=10000"
driver.execute_script(js)

三、滾動條拉到指定位置(具體元素):--最經常使用

target = driver.find_element_by_id("id_keypair")
driver.execute_script("arguments[0].scrollIntoView();", target)

四、經過模擬鍵盤DOWN(↓)來拖動:

driver.find_element_by_id("id").send_keys(Keys.DOWN)

五、scrollTo函數

--scrollHeight 獲取對象的滾動高度。 

--scrollLeft 設置或獲取位於對象左邊界和窗口中目前可見內容的最左端之間的距離。 

--scrollTop 設置或獲取位於對象最頂端和窗口中可見內容的最頂端之間的距離。 

--scrollWidth 獲取對象的滾動寬度。

 

#滾動到底部

js = "window.scrollTo(0,document.body.scrollHeight)"
driver.execute_script(js)

#滾動到頂部

js = "window.scrollTo(0,0)"
driver.execute_script(js)

2、參考代碼

 
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : jss.py
# @Software: PyCharm
 
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys
url = 'http://www.cnblogs.com/sanzangTst/'
browser = webdriver.Firefox()
browser.get(url)
time.sleep(3)
 
# 拉到底部
js="var q=document.documentElement.scrollTop=10000"
browser.execute_script(js)
 
# 回到頂部 
js="var q=document.documentElement.scrollTop=0"
browser.execute_script(js)
 
# 拖到指定位置
target = browser.find_element_by_id("homepage1_HomePageDays_DaysList_ctl05_DayList_TitleUrl_0")
browser.execute_script("arguments[0].scrollIntoView();", target)
 
#滾動到底部
js = "window.scrollTo(0,document.body.scrollHeight)"
browser.execute_script(js)
 
#滾動到頂部
js = "window.scrollTo(0,0)"
browser.execute_script(js)

 

 固然,JavaScript的做用不只僅體如今瀏覽器滾動條的操做上,還能夠用它向頁面中textarea文本框輸入內容。

......
<textarea id="id" style="width: 98%" cols="50" rows="5" class="textarea">
</textarea>
......

  雖然咱們能夠經過id的方式將其進行定位,但卻不能經過send_keys()向文本框中輸入文本信息。這種狀況下,就須要藉助JavaScript代碼完成輸入。

......
text = "input text"
js = "var sum=document.getElementById("id"); sum.value = '" + text + "';"
driver.execute_script(js)
......

  首先定義了要輸入的內容text,而後將text與JavaScript代碼經過 「+」 進行拼接。這樣作的目的是爲了使輸入內容變得可自定義。最後,經過execute_script()執行JavaScript代碼。

2.16 處理HTML5的視頻播放

  目前 HTML5 技術已漸漸成爲主流,主流的瀏覽器都已支持 HTML5。愈來愈多的應用使用了 HTML5 的元素,如canvas、video等,另外網頁存儲功能更增長了用戶的網絡體驗,使得愈來愈多的開發者在使用這樣的標準,因此咱們也須要學習如何使用自動化技術來測試它們。

  WebDriver 支持在指定的瀏覽器上測試 HTML5,另外,咱們還能夠使用 JavaScript 來測試這些功能,這樣就能夠在任何瀏覽器上測試HTML5了。

  大多數瀏覽器使用控件(如Flash)來播放視頻,可是,不一樣的瀏覽器須要使用不一樣的插件。HTML5定義了一個新的元素<video>,指定了一個標準的方式來嵌入電影片斷。

from selenium import webdriver
from time import sleep

driver = webdriver.Firefox()
driver.get("http://videojs.com/")

video = driver.find_element_by_xpath("body/Setion[1]/div/video")

# 返回播放文件地址
url = driver.execute_script("return arguments[0].currentSrc;",video)
print(url)

# 播放視頻
print("start")
driver.execute_script("return arguments[0].play()",video)

# 播放15秒鐘
sleep(15)

# 暫停視頻
print("stop")
driver.execute_script("arguments[0].pause()",video)

driver.quit()

  JavaScript 函數有個內置的對象叫作 arguments。arguments對象包含了函數調用的參數數組,[0]表示取對象的第1個值。

  currentSrc 熟悉返回當前音頻 / 視頻的URL。若是未設置音頻 / 視頻,則返回空字符串。

  load() 、play() 、pause() 、等控制着視頻的加載、播放和暫停。

 

 2.17 窗口截圖

  自動化用例是由程序去執行的,所以有時候打印的錯誤信息並不十分明確。若是在腳本執行出錯的時候能對當前窗口截圖保存,那麼經過圖片就能夠很是直觀地看出出錯的緣由。WebDriver提供了截圖函數 get_screenshot_as_file() 來截取當前窗口。

driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
sleep(2)

# 截圖當前窗口,並制定截圖圖片的保存位置
driver.get_screenshot_as_file("D:\\pyse\\baidu_img.png")   # png格式
driver.quit()

 2.18 關閉窗口

  在前面的例子中咱們一直使用 quit() 方法,其含義爲退出相關的驅動程序和關閉全部窗口。除此以外,WebDriver還提供了close()方法,用來關閉當前窗口。在用例執行的過程當中打開了多個窗口,咱們想要關閉其中的某個窗口,這時就要用到 close() 方法進行關閉了。

 

2.19 驗證碼的處理

  對於Web應用來講,大部分的系統在用戶登陸時都要求用戶輸入驗證碼。驗證碼的類型不少,有字母數字的,有漢字的,甚至還有須要用戶輸入一道算術題的答案的。對於系統來講,使用驗證碼能夠有效地防止採用機器猜想方法對口令的刺探,在必定程度上增長了安全性。

  但對測試人員來講,無論是進行性能測試仍是自動化測試,都是一個比較棘手的問題。在WebDriver中並無提供相應的方法來處理驗證碼,這裏有幾種處理驗證碼的常見方法。

  1. 去掉驗證碼

  這是最簡單的方法,對於見解人員來講,只是把驗證碼的相關代碼註釋掉便可。若是是在測試環境,這樣作可省去測試人員很多的麻煩;但若是自動化腳本是在正是環境測試,那麼這種作法就給系統帶來了必定的風險。

  2. 設置萬能驗證碼

  去掉驗證碼的主要問題是安全,爲了應對在線系統的安全威脅,能夠在修改程序時不取消驗證碼,而是在程序中留一個「後門」,即設置一個「萬能驗證碼」。只要用戶輸入這個「萬能驗證碼」,程序就認爲驗證經過,不然就判斷用戶輸入的驗證碼是否正確。

  設計萬能驗證碼的方式很是簡單,只需對用戶的輸入信息多加一個邏輯判斷。

  3. 驗證碼識別技術

  例如,能夠經過Python-tesseract 來識別圖片驗證碼。Python-tesseract是光學字符識別 Tesseract OCR 引擎的Python封裝類,可以讀取任何常規的圖片文件(JPG/GIF/PNG/TIFF等)。不過,目前市面上的驗證碼形式繁多,大多驗證碼識別技術,識別率都很難達到100%。

  4. 記錄cookie

  經過向瀏覽器中添加cookie能夠繞過登陸的驗證碼,這是比較有意思的一種解決方案。例如咱們在第一次登陸某網站時勾選「記住密碼」的選項,當下次再訪問該網站時自動就處於登錄狀態了。這樣天然就繞過了驗證碼問題。這個「記住密碼」功能其實就記錄在了瀏覽器的cookie中。前面已經學了經過WebDriver來操做瀏覽器的cookie,能夠經過add_cookie() 方法將用戶名密碼寫入瀏覽器cookie,當再次訪問網站時,服務器將直接讀取瀏覽器的cookie進行登陸。

......
# 訪問 xx 網站
driver.get("http://www.xx.cn")

# 將用戶名密碼寫入瀏覽器 cookie
driver.add_cookie({"name":"Login_UserNumber","value":"username"})
driver.add_cookie({"name":"Login_Passwd","value":"password"})

# 再次訪問xx網站,將會自動登陸
driver.get("http://www.xx.cn/")
#......

driver.quit()

  這種方式最大的問題是如何從瀏覽器的 cookie 中找到用戶名和密碼對應的 key 值,並傳入對應的登陸信息。能夠用 get_cookies()方法來獲取登陸的全部的cookie信息,從中找到用戶名和密碼的key。固然,更直接的方式是詢問開發人員。

 

 4.20 WebDriver 原理

  WebDriver 是按照 Server - Client 的經典設計模式設計的。

  Server 端就是 Remote Server,能夠是任意的瀏覽器。當咱們的腳本啓動瀏覽器後,該瀏覽器就是Remote Server,它的職業就是等待 Client 發送請求並做出響應。

  Client 端簡單說來就是咱們的測試代碼。咱們測試代碼中的一些行爲,例如打開瀏覽器,轉跳到特定的 URL 等操做是以 http 請求的方式發送給被測試瀏覽器的,也就是 Remote Server。Remote Server。Remote Server 接受請求,執行相應操做,並在 Response 中返回執行狀態,返回值等信息。

  WebDriver 的工做流程:

  1. WebDriver 啓動目標瀏覽器,並綁定到指定端口。啓動的瀏覽器實例將做爲 WebDriver 的 Remote Server。
  2. Client 端經過 CommandExcuter 發送 HTTPRequest 給Remote Server 的偵聽端口(通訊協議:the webdriver wire protocol)
  3. Remote Server 須要依賴原生的瀏覽器組件(如IEDriverServer.exe、chromedriver.exe)來轉化瀏覽器的 native 調用。

  Python 提供了logging 模塊給運行中的應用提供了一個標準的信息輸出接口。它提供了basicConfig() 方法用於基本信息的定義。開啓 debug 模塊,就能夠捕捉到客戶端向服務端發送的請求。

from selenium import webdriver
import logging

logging.basicConfig(level = logging.DEBUG)
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")

driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
driver.quit()

>>>
C:\Users\Administrator\AppData\Local\Programs\Python\Python37\python.exe C:/Users/Administrator/Desktop/py/test.py
DEBUG:selenium.webdriver.remote.remote_connection:POST http://127.0.0.1:3633/session {"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName": "firefox", "acceptInsecureCerts": true}}, "desiredCapabilities": {"browserName": "firefox", "acceptInsecureCerts": true, "marionette": true}}
DEBUG:selenium.webdriver.remote.remote_connection:b'{"value": {"sessionId":"84ddc3fe-d7af-4d2e-a5bb-a7408100b3aa","capabilities":{"acceptInsecureCerts":true,"browserName":"firefox","browserVersion":"61.0","moz:accessibilityChecks":false,"moz:headless":false,"moz:processID":18244,"moz:profile":"C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Temp\\\\rust_mozprofile.OvsTh3aeSztY","moz:useNonSpecCompliantPointerOrigin":false,"moz:webdriverClick":true,"pageLoadStrategy":"normal","platformName":"windows_nt","platformVersion":"10.0","rotatable":false,"timeouts":{"implicit":0,"pageLoad":300000,"script":30000}}}}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
DEBUG:selenium.webdriver.remote.remote_connection:POST http://127.0.0.1:3633/session/84ddc3fe-d7af-4d2e-a5bb-a7408100b3aa/url {"url": "http://www.baidu.com"}
DEBUG:selenium.webdriver.remote.remote_connection:b'{"value": null}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
DEBUG:selenium.webdriver.remote.remote_connection:POST http://127.0.0.1:3633/session/84ddc3fe-d7af-4d2e-a5bb-a7408100b3aa/element {"using": "css selector", "value": "[id=\"kw\"]"}
DEBUG:selenium.webdriver.remote.remote_connection:b'{"value":{"element-6066-11e4-a52e-4f735466cecf":"2f5d6f4b-81aa-425f-9a12-9b6b1b81c602"}}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
DEBUG:selenium.webdriver.remote.remote_connection:POST http://127.0.0.1:3633/session/84ddc3fe-d7af-4d2e-a5bb-a7408100b3aa/element/2f5d6f4b-81aa-425f-9a12-9b6b1b81c602/value {"text": "selenium", "value": ["s", "e", "l", "e", "n", "i", "u", "m"], "id": "2f5d6f4b-81aa-425f-9a12-9b6b1b81c602"}
DEBUG:selenium.webdriver.remote.remote_connection:b'{"value": null}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
DEBUG:selenium.webdriver.remote.remote_connection:POST http://127.0.0.1:3633/session/84ddc3fe-d7af-4d2e-a5bb-a7408100b3aa/element {"using": "css selector", "value": "[id=\"su\"]"}
DEBUG:selenium.webdriver.remote.remote_connection:b'{"value":{"element-6066-11e4-a52e-4f735466cecf":"d1ec924a-2bfa-4739-b3a0-e3f721319bee"}}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
DEBUG:selenium.webdriver.remote.remote_connection:POST http://127.0.0.1:3633/session/84ddc3fe-d7af-4d2e-a5bb-a7408100b3aa/element/d1ec924a-2bfa-4739-b3a0-e3f721319bee/click {"id": "d1ec924a-2bfa-4739-b3a0-e3f721319bee"}
DEBUG:selenium.webdriver.remote.remote_connection:b'{"value": null}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request
DEBUG:selenium.webdriver.remote.remote_connection:DELETE http://127.0.0.1:3633/session/84ddc3fe-d7af-4d2e-a5bb-a7408100b3aa {}
DEBUG:selenium.webdriver.remote.remote_connection:b'{"value": null}'
DEBUG:selenium.webdriver.remote.remote_connection:Finished Request

Process finished with exit code 0

  basicConfig 所捕捉的log信息。不過basicConfig()開啓的debug模式只能捕捉到客戶端向服務器發送的 POST 請求,而沒法獲取服務器所返回的應答信息。Selenium Server 能夠獲取到更詳細的請求與應答信息。

 可參考別人的博客:Selenium-WebDriverApi接口詳解

相關文章
相關標籤/搜索