閱在線 AIP 文檔:
http://selenium.googlecode.com/git/docs/api/py/index.html
目錄
一、selenium+python 環境搭建................................................................................................6
1.1 selenium 介紹............................................................................................................... 6
1.2 准備工作......................................................................................................................6
1.3 安裝步驟......................................................................................................................7
1.4 安裝chrome driver......................................................................................................8
1.5 安裝 IE driver................................................................................9
二、開始第一個腳本.................................................................................................................9
2.1 為什么選python..........................................................................................................9
2.2 第一個腳本..................................................................................................................9
2.3 腳本解析....................................................................................................................10
三、元素的定位.......................................................................................................................11
3.1 id 和 name 定位.......................................................................................................12
3.2 tagname 和 class name定位...................................................................................12
3.3 CSS 定位..................................................................................................................13
3.4 XPath 定位...............................................................................................................14
3.5 link 定位...................................................................................................................15
3.6 Partial link text 定位................................................................................................15
四、添加等待時間...................................................................................................................15
4.1、添加休眠..................................................................................................................15
4.2、智能等待..................................................................................................................16
五、打印信息...........................................................................................................................17
5.1、打印 tile....................................................................................................................17
5.2、打印 URL.................................................................................................................17
六、瀏覽器的操作...................................................................................................................18
6.1、瀏覽器最大化..........................................................................................................18
6.2、設置瀏覽器寬、高..................................................................................................19
七、操作瀏覽器的前進、后退...............................................................................................19
八、操作測試對象...................................................................................................................20
8.1、鼠標點擊與鍵盤輸入..............................................................................................21
8.2、submit 提交表單......................................................................................................21
8.3、text獲取元素文本...................................................................................................22
8.4、get_attribute 獲得屬性值........................................................................................ 22
九、鍵盤事件...........................................................................................................................23
9.1、鍵盤按鍵用法..........................................................................................................23
9.2、鍵盤組合鍵用法......................................................................................................24
9.3、中文亂碼問題..........................................................................................................25
十、鼠標事件...........................................................................................................................25
10.1、鼠標右鍵................................................................................................................26
博客園 — 蟲師
http://fnng.cnblogs.com 4
10.2、鼠標雙擊................................................................................................................27
10.3、鼠標拖放................................................................................................................27
十一、定位一組元素...............................................................................................................28
11.1、第一種定位方法....................................................................................................30
11.2、第二種定位方法....................................................................................................31
11.3、去掉最后一個勾選................................................................................................31
十二、多層框架/窗口定位......................................................................................................32
12.1、多層框架定位........................................................................................................32
12.2、多層窗口定位........................................................................................................35
十三、層級定位.......................................................................................................................35
十四、上傳文件操作...............................................................................................................38
14.1、操作文件上傳例子................................................................................................39
14.2、139 郵箱上傳.........................................................................................................40
十五、下拉框處理...................................................................................................................41
15.1、操作下拉框例子....................................................................................................41
15.2、百度搜索設置下拉框操作....................................................................................43
十六、alert、confirm、prompt 的處理..................................................................................44
十七、對話框的處理...............................................................................................................45
17.1、div 對話框的處理..................................................................................................45
17.2、一般對話框的處理................................................................................................48
十八、調用 js...........................................................................................................................49
18.1、通過 js 隱藏元素...................................................................................................49
18.2、通過 js 使輸入框標紅...........................................................................................51
十九、控制瀏覽器滾動條.......................................................................................................52
19.1、場景一....................................................................................................................53
19.2、場景二....................................................................................................................53
二十、cookie 處理...................................................................................................................54
20.1、打印 cookie 信息...................................................................................................54
20.2、對cookie 操作.......................................................................................................55
20.3、博客園登陸分析cookie........................................................................................56
二十一、webdriver 原理解析................................................................................................. 57
二十二、引入 unittest 框架.....................................................................................................65
二十三、unittest 單元測試框架解析......................................................................................70
二十四、批量執行測試集.......................................................................................................75
二十五、異常捕捉與錯誤截圖...............................................................................................77
二十六、生成測試報告(HTMLTestRunner).......................................................................... 80
二十七、數據驅動測試...........................................................................................................83
27.1、讀取文件參數化....................................................................................................83
27.2、用戶名密碼的參數化(讀取文件)................................................................... 85
27.3、用戶名的參數化(字典)....................................................................................86
27.4、用戶名密碼的參數化(函數)........................................................................... 87
二十八、測試套件...................................................................................................................89
28.1、測試套件實例........................................................................................................89
28.2、整合 HTMLTestRunner 測試報告........................................................................93
博客園 — 蟲師
http://fnng.cnblogs.com 5
28.3、更易讀的報告........................................................................................................95
二十九、結構改進...................................................................................................................96
29.1、all_tests.py 移出來................................................................................................96
29.2、__init__.py 文件解析............................................................................................97
29.3、調用多級目錄的用例............................................................................................98
29.4、改進用例的讀取....................................................................................................99
29.5、進一步分離用例列表..........................................................................................101
三十、UliPad--python 開發利器...........................................................................................103
一、selenium+python 環境搭建
1.1selenium 介紹
selenium 是一個 web 的自動化測試工具,不少學習功能自動化的同學開始首選 selenium ,
相因為它相比 QTP有諸多有點:
* 免費,也不用再為破解 QTP 而大傷腦筋
* 小巧,對於不同的語言它只是一個包而已,而 QTP 需要下載安裝1個多 G 的程序。
* 這也是最重要的一點,不管你以前更熟悉 C、 java、ruby、python、或都是 C# ,你都
可以通過 selenium 完成自動化測試,而 QTP 只支持 VBS
* 支持多平台:windows、linux、MAC ,支持多瀏覽器:ie、ff、safari、opera、chrome
* 支持分布式測試用例的執行,可以把測試用例分布到不同的測試機器的執行,相當於分
發機的功能。
1.2 准備工作
搭建平台 windows
准備工具如下:
-------------------------------------------------------------
下載 python
http://python.org/getit/
下載 setuptools 【python的基礎包工具】
http://pypi.python.org/pypi/setuptools
下載 pip 【python 的安裝包管理工具】
https://pypi.python.org/pypi/pip
-------------------------------------------------------------
因為版本都在更新,pyhton 選擇2.7.xx ,setuptools 選擇你平台對應的版本,pip 不要
擔心 tar.gz 在 windows 下一樣可用。
1.3 安裝步驟
一、python 的安裝 ,這個不解釋,exe 文件運行安裝即可,既然你選擇 python,相信
你是熟悉 python 的,我安裝目錄 C:\Python27
二、setuptools 的安裝也非常簡單,同樣是 exe 文件,默認會找到 python 的安裝路徑,
將安裝到 C:\Python27\Lib\site-packages 目錄下
三、安裝 pip ,我默認解壓在了 C:\pip-1.3.1 目錄下
四、打開命令提示符(開始---cmd 回車)進入 C:\pip-1.3.1目錄下輸入:
C:\pip-1.3.1 >python setup.pyinstall
(如果提示 python 不是內部或外部命令!別急,去配置一下環境變量吧)
修改我的電腦->屬性->高級->環境變量->系統變量中的 PATH 為:
變量名:PATH
變量值:;C:\Python27
五、再切換到 C:\Python27\Scripts 目錄下輸入:
C:\Python27\Scripts> easy_install pip
六、安裝 selenium,(下載地址: https://pypi.python.org/pypi/selenium )
如果是聯網狀態的話,可以直接在 C:\Python27\Scripts 下輸入命令安裝:
C:\Python27\Scripts> pip install -U selenium
如果沒聯網(這個一般不太可能),下載 selenium 2.33.0 (目前的最新版本)
並解壓把整個目錄放到 C:\Python27\Lib\site-packages 目錄下。
注意:七、八兩步可以暫不進行,如果你要學習第二十一章 webdriver 原理的時候再進行
也不遲。
==============
七、下載並安裝
(http://www.java.com/zh_CN/download/chrome.jsp?locale=zh_CN),什么!?你沒整過
java 虛擬機,百度一下 java 環境搭建吧。
八、下載 selenium 的服務端(https://code.google.com/p/selenium/)在頁面的左
側列表中找到
selenium-server-standalone-XXX.jar
對!就是這個東西,把它下載下來並解壓;
在 selenium-server-standalone-xxx.jar 目 錄 下 使 用 命 令 java -jar
selenium-server-standalone-xxx.jar 啟動(如果打不開,查看是否端口被占用:netstat
-aon|findstr 4444)。
==============
1.4 安裝 chrome driver
chrome driver 的下載地址在這里。
1. 下載解壓,你會得到一個 chromedriver.exe 文件(我點開,運行提示 started no prot
9515 ,這是干嘛的?端口9515被占了?中間折騰了半天),后來才知道需要把這家伙放到
chrome 的安裝目錄下...\Google\Chrome\Application\ ,然后設置 path 環境變量,把
chrome 的安裝目錄(我的:C:\Program Files\Google\Chrome\Application),然后再調用
運行:
# coding = utf-8
fromselenium import webdriver
driver =webdriver.Chrome()
driver.get('http://radar.kuaibo.com')
print driver.title
driver.quit()
報錯提示:
Chrome version must be >= 27.0.1453.0\n (Driver info:
chromedriver=2.0,platform=Windows NT 5.1 SP3 x86)
說我 chrome 的版本沒有大於27.0.1453.0 ,這個好辦,更新到最新版本即可。
博客園 — 蟲師
http://fnng.cnblogs.com 9
1.5 安裝IE driver
在新版本的 webdriver中,只有安裝了 ie driver使用 ie 進行測試工作。
ie driver 的下載地址在這里,記得根據自己機器的操作系統版本來下載相應的 driver。
暫時還沒嘗試,應該和 chrome 的安裝方式類似。
記得配置 IE 的保護模式
如果要使用 webdriver啟動 IE 的話,那么就需要配置 IE 的保護模式了。
把 IE 里的保護模式都選上或都勾掉就可以了。
二、開始第一個腳本
2.1 為什么選 python
之前的菜鳥系列是基於 java 的,一年沒學其實也忘的差不多了,目前所測的產品
部分也是 python 寫的,而且團隊也在推廣 python ,其實就測試人員來說,python 也
相當受歡迎。易學,易用。翻翻各測試招聘,python 出現的概率也頗高。(個人原因)
最重要的還是 python 簡單易學,應用也相對廣泛;是測試人員學習編程的不二之選。
下面看看 python 穿上 seleniumwebdriver 是多么的性感:
2.2 第一個腳本
#coding = utf-8
from selenium import webdriver
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
browser.find_element_by_id("kw" ).send_keys( "selenium")
browser.find_element_by_id("su").click()
博客園 — 蟲師
http://fnng.cnblogs.com 10
browser.quit()
2.3 腳本解析
# coding = utf-8
可加可不加,開發人員喜歡加一下,防止亂碼嘛。
from selenium import webdriver
要想使用 selenium 的 webdriver里的函數,首先把包導進來嘛
browser = webdriver.Firefox()
我們需要操控哪個瀏覽器呢?Firefox ,當然也可以換成 Ie 或 Chrome 。browser 可以
隨便取,但后面要用它操縱各種函數執行。
browser.find_element_by_id("kw").send_keys("selenium")
一個控件有若干屬性 id 、name、(也可以用其它方式定位),百度輸入框的 id 叫 kw ,
我要在輸入框里輸入 selenium 。多自然語言呀!
browser.find_element_by_id("su").click()
搜索的按鈕的 id 叫 su ,我需要點一下按鈕( click() )。
browser.quit()
退出並關閉窗口的每一個相關的驅動程序,有潔癖用這個。
browser.close()
關閉當前窗口 ,用哪個看你的需求了。
博客園 — 蟲師
http://fnng.cnblogs.com 11
三、元素的定位
對象的定位應該是自動化測試的核心,要想操作一個對象,首先應該識別這個對象。
一個對象就是一個人一樣,他會有各種的特征(屬性),如比我們可以通過一個人的身
份證號,姓名,或者他住在哪個街道、樓層、門牌找到這個人。
那么一個對象也有類似的屬性,我們可以通過這個屬性找到這對象。
webdriver 提供了一系列的對象定位方法,常用的有以下幾種
· id
· name
· class name
· link text
· partial link text
· tag name
· xpath
· css selector
我們可以看到,一個百度的輸入框,可以用這么用種方式去定位。
<input id="kw" class="s_ipt" type="text" maxlength="100" name="wd"
autocomplete="off">
#coding=utf-8
fromselenium import webdriver
browser =webdriver.Firefox()
browser.get("http://www.baidu.com")
#########百度輸入框的定位方式##########
#通過 id 方式定位
browser.find_element_by_id("kw").send_keys("selenium")
#通過 name 方式定位
browser.find_element_by_name("wd").send_keys("selenium")
#通過 tag name 方式定位
browser.find_element_by_tag_name("input").send_keys("selenium")
#通過 class name 方式定位
browser.find_element_by_class_name("s_ipt").send_keys("selenium")
博客園 — 蟲師
http://fnng.cnblogs.com 12
#通過 CSS 方式定位
browser.find_element_by_css_selector("#kw").send_keys("selenium")
#通過 xphan 方式定位
browser.find_element_by_xpath("//input[@id='kw']").send_keys("selenium")
############################################
browser.find_element_by_id("su").click()
time.sleep(3)
browser.quit()
3.1 id 和 和 name 定位
id 和 name 是我們最最常用的定位方式,因為大多數控件都有這兩個屬性,而且
在對控件的 id 和 name 命名時一般使其有意義也會取不同的名字。通過這兩個屬性使我
們找一個頁面上的屬性變得相當容易
我們通過前端工具,找到了百度輸入框的屬性信息,如下:
<input id="kw" class="s_ipt" type="text" maxlength="100" name="wd"
autocomplete="off">
id=”kw”
通過 find_element_by_id("kw") 函數就是捕獲到百度輸入框
name=”wd”
通過 find_element_by_name("wd")函數同樣也可以捕獲百度輸入框
3.2 tag name 和 和 class name 定位
從上面的百度輸入框的屬性信息中,我們看到,不單單只有 id 和 name 兩個屬性,
比如 class 和 tag name(標簽名)
<input id="kw" class="s_ipt" type="text" maxlength="100" name="wd"
autocomplete="off">
<input>
博客園 — 蟲師
http://fnng.cnblogs.com 13
input就是一個標簽的名字,可以通過 find_element_by_tag_name("input") 函數來定
位。
class="s_ipt"
通過 find_element_by_class_name("s_ipt")函數捕獲百度輸入框。
3.3 CSS 定位
CSS(Cascading Style Sheets)是一種語言,它被用來描述 HTML 和 XML 文檔的表現。
CSS 使用選擇器來為頁面元素綁定屬性。這些選擇器可以被 selenium 用作另外的定位策
略。
CSS 的比較靈活可以選擇控件的任意屬性,上面的例子中:
find_element_by_css_selector("#kw")
通過 find_element_by_css_selector( )函數,選擇取百度輸入框的id 屬性來定義
也可以取 name 屬性
<a href="http://news.baidu.com" name="tj_news">新 聞</a>
driver.find_element_by_css_selector("a[name=\"tj_news\"]").click()
可以取 title屬性
<a onclick="queryTab(this);" mon="col=502&pn=0" title="web"
href="http://www.baidu.com/">網頁</a>
driver.find_element_by_css_selector("a[title=\"web\"]").click()
也可以是取..:
<a class="RecycleBin xz" href="javascript:void(0);">
driver.find_element_by_css_selector("a.RecycleBin").click()
雖然我也沒全部理解 CSS 的定位,但是看上去應該是一種非常靈活和牛 X 的定位方式
擴展閱讀:
http://www.w3.org/TR/css3-selectors/
博客園 — 蟲師
http://fnng.cnblogs.com 14
http://www.w3school.com.cn/css/css_positioning.asp
3.4 XPath 定位
什么是 XPath:http://www.w3.org/TR/xpath/
XPath 基礎教程:http://www.w3schools.com/xpath/default.asp
selenium 中被誤解的 XPath : http://magustest.com/blog/category/webdriver/
XPath 是一種在 XML 文檔中定位元素的語言。因為 HTML 可以看做 XML 的一種實現,
所以 selenium 用戶可是使用這種強大語言在 web 應用中定位元素。
XPath 擴展了上面 id和 name 定位方式,提供了很多種可能性,比如定位頁面上的
第三個多選框。
xpath:attributer (屬性)
driver.find_element_by_xpath("//input[@id='kw']").send_keys("selenium")
#input 標簽下 id =kw 的元素
xpath:idRelative (id 相關性)
driver.find_element_by_xpath("//div[@id='fm']/form/span/input").send_keys("s
elenium")
#在/form/span/input 層級標簽下有個 div標簽的 id=fm 的元素
driver.find_element_by_xpath("//tr[@id='check']/td[2]").click()
# id 為'check' 的 tr ,定位它里面的第2個 td
xpath:position (位置)
driver.find_element_by_xpath("//input").send_keys("selenium")
driver.find_element_by_xpath("//tr[7]/td[2]").click()
#第7個 tr 里面的第2個td
xpath: href (水平參考)
driver.find_element_by_xpath("//a[contains(text(),'網頁')]").click()
#在 a 標簽下有個文本(text)包含(contains)'網頁' 的元素
xpath:link
driver.find_element_by_xpath("//a[@href='http://www.baidu.com/']").click()
#有個叫 a 的標簽,他有個鏈接 href='http://www.baidu.com/ 的元素
博客園 — 蟲師
http://fnng.cnblogs.com 15
3.5 link 定位
有時候不是一個輸入框也不是一個按鈕,而是一個文字鏈接,我們可以通過 link
#coding=utf-8
fromselenium import webdriver
browser =webdriver.Firefox()
browser.get("http://www.baidu.com")
browser.find_element_by_link_text("貼 吧").click()
browser.quit()
一般一個頁面上不會出現相同的文件鏈接,通過文字鏈接來定位也是一種簡單有效
的定位方式。
3.6 Partiallink text 定位
通過部分鏈接定位,這個有時候也會用到,我還沒有想到很好的用處。拿上面的例
子,我可以只用鏈接的一部分文字進行匹配:
browser.find_element_by_partial_link_text("貼").click()
#通過 find_element_by_partial_link_text() 函數,我只用了“貼”字,腳本一樣找到了"貼 吧
" 的鏈接
四、添加等待時間
有時候為了保證腳本運行的穩定性,需要腳本中添加等待時間。
4.1 、添加休眠
添加休眠非常簡單,我們需要引入 time 包,就可以在腳本中自由的添加休眠時間了。
# coding = utf-8
博客園 — 蟲師
http://fnng.cnblogs.com 16
fromselenium import webdriver
import time #調入 time 函數
browser =webdriver.Firefox()
browser.get("http://www.baidu.com")
time.sleep(0.3) #休眠0.3秒
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3) # 休眠3秒
browser.quit()
4.2 、智能等待
通過添加 implicitly_wait() 方法就可以方便的實現智能等待;implicitly_wait(30)
的用法應該比 time.sleep() 更智能,后者只能選擇一個固定的時間的等待,前者可以
在一個時間范圍內智能的等待。
文檔解釋:
selenium.webdriver.remote.webdriver.implicitly_wait(time_to_wait)
隱式地等待一個無素被發現或一個命令完成;這個方法每次會話只需要調用一次
time_to_wait: 等待時間
用法:
browser.implicitly_wait(30)
# coding = utf-8
fromselenium import webdriver
import time #調入 time 函數
browser =webdriver.Firefox()
browser.get("http://www.baidu.com")
browser.implicitly_wait(30) #智能等待30秒
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
browser.quit()
博客園 — 蟲師
http://fnng.cnblogs.com 17
五、打印信息
很多時間我們不可能盯着腳本執行,我們需要一些打印信息來證明腳本運行是否正確:
5.1 、打印 tile
把剛才訪問頁面的 title 打印出來。
coding = utf-8
fromselenium import webdriver
driver = webdriver.Chrome()
driver.get('http://www.baidu.com')
print driver.title # 把頁面 title 打印出來
driver.quit()
雖然我沒看到腳本的執行過程,但我在執行結果里看到了
>>>
百度一下,你就知道
說明頁面正確被我打開了。
5.2 、打印 URL
可以將瀏覽器的 title 打印出來,這里再講個簡單的,把當前 URL 打印出來。其實
也沒啥大用,可以做個湊數的用例。
#coding=utf-8
fromselenium import webdriver
import time
browser =webdriver.Firefox()
url='http://www.baidu.com'
博客園 — 蟲師
http://fnng.cnblogs.com 18
#通過 get 方法獲取當前 URL 打印
print "now access %s" %(url)
browser.get(url)
time.sleep(2)
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3)
browser.quit()
六、瀏覽器的操作
6.1 、瀏覽器最大化
我們知道調用啟動的瀏覽器不是全屏的,這樣不會影響腳本的執行,但是有時候會
影響我們“觀看”腳本的執行。
#coding=utf-8
fromselenium import webdriver
import time
browser =webdriver.Firefox()
browser.get("http://www.baidu.com")
print "瀏覽器最大化"
browser.maximize_window() #將瀏覽器最大化顯示
time.sleep(2)
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3)
browser.quit()
博客園 — 蟲師
http://fnng.cnblogs.com 19
6.2 、設置瀏覽器寬、高
最大化還是不夠靈活,能不能隨意的設置瀏覽的寬、高顯示?當然是可以的。
#coding=utf-8
from selenium import webdriver
import time
browser =webdriver.Firefox()
browser.get("http://m.mail.10086.cn")
time.sleep(2)
#參數數字為像素點
print "設置瀏覽器寬480、高800顯示"
browser.set_window_size(480, 800) time.sleep(3)
browser.quit()
七、操作瀏覽器的前進、后退
瀏覽器上有一個后退、前進按鈕,對於瀏覽網頁的人是比較方便的;對於做 web 自
動化測試的同學來說應該算是一個比較難模擬的問題;其實很簡單,下面看看 python
的實現方式。
#coding=utf-8
fromselenium import webdriver
import time
browser =webdriver.Firefox()
#訪問百度首頁
first_url= 'http://www.baidu.com'
博客園 — 蟲師
http://fnng.cnblogs.com 20
print "now access %s" %(first_url)
browser.get(first_url)
time.sleep(2)
#訪問新聞頁面
second_url='http://news.baidu.com'
print "now access %s" %(second_url)
browser.get(second_url)
time.sleep(2)
#返回(后退)到百度首頁
print "back to %s "%(first_url)
browser.back()
time.sleep(1)
#前進到新聞頁
print "forwardto %s"%(second_url)
browser.forward()
time.sleep(2)
browser.quit()
為了使過程讓你看得更清晰,在每一步操作上都加了 print和 sleep 。
說實話,這兩個功能平時不太常用,所能想到的場景就是幾個頁面來回跳轉,但又
不想用 get url 的情況下。
八、操作測試對象
前面講到了不少知識都是定位元素,定位只是第一步,定位之后需要對這個原素進
行操作。鼠標點擊呢還是鍵盤輸入,這要取決於我們定位的是按鈕還輸入框。
博客園 — 蟲師
http://fnng.cnblogs.com 21
一般來說,webdriver 中比較常用的操作對象的方法有下面幾個
click 點擊對象
send_keys 在對象上模擬按鍵輸入
clear 清除對象的內容,如果可以的話
submit 清除對象的內容,如果可以的話
text 用於獲取元素的文本信息
8.1 、鼠標點擊與鍵盤輸入
在我們本系列開篇的第一個例子里就用到了到 click 和 send_skys ,別翻回去找
了,我再貼一下代碼:
coding=utf-8
fromselenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(2)
#通過 submit() 來操作
driver.find_element_by_id("su").submit()
time.sleep(3)
driver.quit()
send_keys("xx") 用於在一個輸入框里輸入 xx 內容。
click() 用於點擊一個按鈕。
clear() 用於清除輸入框的內容,比如百度輸入框里默認有個“請輸入關鍵
字”的信息,再比如我們的登陸框一般默認會有“賬號”“密碼”這樣的默認信息。
clear 可以幫助我們清除這些信息。
8.2 、submit 提交表單
我們把“百度一下”的操作從 click 換成 submit 可以達到相同的效果:
#coding=utf-8
fromselenium import webdriver
import time
博客園 — 蟲師
http://fnng.cnblogs.com 22
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(2)
#通過 submit() 來操作
driver.find_element_by_id("su").submit()
time.sleep(3)
driver.quit()
8.3 、text 獲取元素文本
text 用於獲取元素的文本信息
下面把百度首頁底部的聲明打印輸出
#coding=utf-8
fromselenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
time.sleep(2)
#id = cp 元素的文本信息
data=driver.find_element_by_id("cp").text
print data #打印信息
time.sleep(3)
driver.quit()
輸出:
>>>
©2013 Baidu使用百度前必讀 京 ICP 證030173號
8.4 、get_attribute 獲得屬性值
get_attribute
博客園 — 蟲師
http://fnng.cnblogs.com 23
獲得屬性值。
這個函數的用法前面已經有出現過,在定位一組元素的時候有使用到它,只是我們
沒有做過多的解釋。
一般用法:
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()
.....
具體應用參考第十一節 層級定位例子。
九、鍵盤事件
本章重點:
鍵盤按鍵用法
鍵盤組合鍵用法
send_keys()輸入中文亂碼問題
9.1 、鍵盤按鍵用法
#coding=utf-8
fromselenium import webdriver
fromselenium.webdriver.common.keys import Keys #需要引入 keys 包
import os,time
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fwebcloud
.kuaibo.com%2F")
博客園 — 蟲師
http://fnng.cnblogs.com 24
time.sleep(3)
driver.maximize_window()# 瀏覽器全屏顯示
driver.find_element_by_id("user_name").clear()
driver.find_element_by_id("user_name").send_keys("fnngj")
#tab 的定位相相於清除了密碼框的默認提示信息,等同上面的 clear()
driver.find_element_by_id("user_name").send_keys(Keys.TAB)
time.sleep(3)
driver.find_element_by_id("user_pwd").send_keys("123456")
#通過定位密碼框,enter(回車)來代替登陸按鈕
driver.find_element_by_id("user_pwd").send_keys(Keys.ENTER)
'''
#也可定位登陸按鈕,通過 enter(回車)代替 click()
driver.find_element_by_id("login").send_keys(Keys.ENTER)
'''
time.sleep(3)
driver.quit()
要想調用鍵盤按鍵操作需要引入keys 包:
fromselenium.webdriver.common.keysimportKeys
通過send_keys()調用按鍵:
send_keys(Keys.TAB) #TAB
send_keys(Keys.ENTER) #回車
注意:這個操作和頁面元素的遍歷順序有關,假如當前定位在賬號輸入框,按鍵
盤的 tab鍵后遍歷的不是密碼框,那就不法輸入密碼。假如輸入密碼后,還有
需要填寫驗證碼,那么回車也起不到登陸的效果。
9.2 、鍵盤組合鍵用法
#coding=utf-8
fromselenium import webdriver
fromselenium.webdriver.common.keys import Keys
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
博客園 — 蟲師
http://fnng.cnblogs.com 25
#輸入框輸入內容
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(3)
#ctrl+a 全選輸入框內容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')
time.sleep(3)
#ctrl+x 剪切輸入框內容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')
time.sleep(3)
#輸入框重新輸入內容,搜索
driver.find_element_by_id("kw").send_keys(u"蟲師 cnblogs")
driver.find_element_by_id("su").click()
time.sleep(3)
driver.quit()
上面的操作沒有實際意義,但向我們演示了鍵盤組合按鍵的用法。
9.3 、中文亂碼問題
selenium2 python 在 send_keys()中輸入中文一直報錯,其實前面加個小 u 就解決了:
coding=utf-8
send_keys(u"輸入中文")
需要注意的是 utf-8並不是萬能的,我們需要保持腳本、瀏覽器、程序三者編碼之
間的轉換;如果 utf-8不能解決,可以嘗試 GBK或修改瀏覽器的默認編碼。
十、鼠標事件
本 章 重點:
ActionChains類
context_click() 右擊
double_click() 雙擊
drag_and_drop() 拖動
測試的產品中有一個操作是右鍵點擊文件列表會彈出一個快捷菜單,可以方
便的選擇快捷菜單中的選擇對文件進行操作(刪除、移動、重命名),之前學習
元素的點擊非常簡單:
driver.find_element_by_id(“xxx”).click()
博客園 — 蟲師
http://fnng.cnblogs.com 26
那么鼠標的雙擊、右擊、拖動等是否也是這樣的寫法呢?例如右擊:
driver.find_element_by_id(“xxx”).context_click()
經過運行腳本得到了下面的錯誤提示:
AttributeError:'WebElement'objecthasnoattribute'context_click'
提示右點方法不屬於 webelement 對象,通過查找文檔,發現屬於
ActionChains類,但文檔中沒有具體寫法。這里要感謝 北京-QC-rabbit 的指
點,其實整個python+selenium學習過程都要感謝北京-QC-rabbit的指點。
10.1 、鼠標右鍵
下面介紹鼠標右鍵的用法,以快播私有雲為例:
#coding=utf-8
fromselenium import webdriver
fromselenium.webdriver.common.action_chainsimport ActionChains
import time
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fwebcloud
.kuaibo.com%2F")
#登陸快播私有雲
driver.find_element_by_id("user_name").send_keys("username")
driver.find_element_by_id("user_pwd").send_keys("123456")
driver.find_element_by_id("dl_an_submit").click()
time.sleep(3)
#定位到要右擊的元素
qqq
=driver.find_element_by_xpath("/html/body/div/div[2]/div[2]/div/div[3]/table
/tbody/tr/td[2]")
#對定位到的元素執行鼠標右鍵操作
ActionChains(driver).context_click(qqq).perform()
博客園 — 蟲師
http://fnng.cnblogs.com 27
'''
#你也可以使用三行的寫法,但我覺得上面兩行寫法更容易理解
chain = ActionChains(driver)
implement=
driver.find_element_by_xpath("/html/body/div/div[2]/div[2]/div/div[3]/table/
tbody/tr/td[2]")
chain.context_click(implement).perform()
'''
time.sleep(3) #休眠3秒
driver.close()
這里需要注意的是,在使用 ActionChains 類之前,要先將包引入。
右擊的操作會了,下面的其它方法比葫蘆畫瓢也能寫出來。
10.2 、鼠標雙擊
鼠標雙擊的寫法:
#定位到要雙擊的元素
qqq =driver.find_element_by_xpath("xxx")
#對定位到的元素執行鼠標雙擊操作
ActionChains(driver).double_click(qqq).perform()
10.3 、鼠標拖放
鼠標拖放操作的寫法:
#定位元素的原位置
element =driver.find_element_by_name("source")
#定位元素要移動到的目標位置
target = driver.find_element_by_name("target")
博客園 — 蟲師
http://fnng.cnblogs.com 28
#執行元素的移動操作
ActionChains(driver).drag_and_drop(element, target).perform()
十一、定位一組元素
webdriver 可以很方便的使用 findElement 方法來定位某個特定的對象,不過有時
候我們卻需要定位一組對象,這時候就需要使用 findElements 方法。
定位一組對象一般用於以下場景:
批量操作對象,比如將頁面上所有的 checkbox 都勾上
先獲取一組對象,再在這組對象中過濾出需要具體定位的一些對象。比如定位出頁
面上所有的 checkbox,然后選擇最后一個
checkbox.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Checkbox</title>
<script type="text/javascript" async=""
src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link
href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined
.min.css" rel="stylesheet"/>
<script
src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></
script>
</head>
<body>
<h3>checkbox</h3>
<div class="well">
<formclass="form-horizontal">
<divclass="control-group">
<labelclass="control-label" for="c1">checkbox1</label>
<div class="controls">
<input type="checkbox" id="c1" />
</div>
</div>
<divclass="control-group">
博客園 — 蟲師
http://fnng.cnblogs.com 29
<labelclass="control-label" for="c2">checkbox2</label>
<div class="controls">
<input type="checkbox" id="c2" />
</div>
</div>
<divclass="control-group">
<labelclass="control-label" for="c3">checkbox3</label>
<div class="controls">
<input type="checkbox" id="c3" />
</div>
</div>
<divclass="control-group">
<labelclass="control-label" for="r">radio</label>
<div class="controls">
<input type="radio" id="r1" />
</div>
</div>
<divclass="control-group">
<labelclass="control-label" for="r">radio</label>
<div class="controls">
<input type="radio" id="r2" />
</div>
</div>
</form>
</div>
</body>
</html>
將這段代碼保存復制到記事本中,將保存成 checkbox.html文件。(注意,這個頁面需要
和我們的自動化腳本放在同一個目錄下)
通過瀏覽器打開,得到下列頁面:
博客園 — 蟲師
http://fnng.cnblogs.com 30
11.1 、第一種定位方法
通過瀏覽器打個這個頁面我們看到三個復選框和兩個單選框。下面我們就來定位這
三個復選框。
# -*- coding: utf-8-*-
fromselenium import webdriver
import time
import os
dr =webdriver.Firefox()
file_path= 'file:///' + os.path.abspath('checkbox.html')
dr.get(file_path)
# 選擇頁面上所有的 input,然后從中過濾出所有的 checkbox 並勾選之
inputs = dr.find_elements_by_tag_name('input')
for inputin inputs:
if input.get_attribute('type') == 'checkbox':
input.click()
time.sleep(2)
dr.quit()
import os
博客園 — 蟲師
http://fnng.cnblogs.com 31
注意:因為我們調用的是本地文件, 所以要導入 os包。
11.2 、第二種定位方法
第二種寫法與第一種寫法差別不大,都是通過一個循環來勾選控件。
# -*- coding: utf-8-*-
fromselenium import webdriver
import time
import os
dr =webdriver.Firefox()
file_path= 'file:///' + os.path.abspath('checkbox.html')
dr.get(file_path)
# 選擇所有的 checkbox 並全部勾上
checkboxes = dr.find_elements_by_css_selector('input[type=checkbox]')
for checkbox in checkboxes:
checkbox.click()
time.sleep(2)
# 打印當前頁面上有多少個 checkbox
print len(dr.find_elements_by_css_selector('input[type=checkbox]'))
time.sleep(2)
dr.quit()
11.3 、去掉最后一個勾選
還有一個問題,有時候我們並不想勾選頁面的所有的復選框(checkbox),可以通
過下面辦法把最后一個被勾選的框去掉。如下:
# -*- coding: utf-8-*-
from selenium import webdriver
import time
import os
dr = webdriver.Firefox()
博客園 — 蟲師
http://fnng.cnblogs.com 32
file_path= 'file:///' + os.path.abspath('checkbox.html')
dr.get(file_path)
# 選擇所有的 checkbox 並全部勾上
checkboxes =
dr.find_elements_by_css_selector('input[type=checkbox]')
for checkbox in checkboxes:
checkbox.click()
time.sleep(2)
# 把頁面上最后1個 checkbox的勾給去掉
dr.find_elements_by_css_selector('input[type=checkbox]').pop().cl
ick()
time.sleep(2)
dr.quit()
其實,去掉勾選表也邏輯也非常簡單,就是再次點擊勾選的按鈕。可能我們比較迷
惑的是如何找到“最后一個”按鈕。pop() 可以實現這個功能。
十二、多層框架/ 窗口定位
本節知識點:
多層框架或窗口的定位:
switch_to_frame()
switch_to_window()
對於一個現代的 web應用,經常會出現框架(frame) 或窗口(window)的應用,
這也就給我們的定位帶來了一個難題。
有時候我們定位一個元素,定位器沒有問題,但一直定位不了,這時候就要檢查這
個元素是否在一個 frame 中,seelnium webdriver 提供了一個 switch_to_frame方
法,可以很輕松的來解決這個問題。
12.1 、多層框架定位
frame.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>frame</title>
博客園 — 蟲師
http://fnng.cnblogs.com 33
<script type="text/javascript"
async=""src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
"></script>
<link
href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstra
p-combined.min.css" rel="stylesheet" />
<script type="text/javascript">$(document).ready(function(){
});
</script>
</head>
<body>
<div class="row-fluid">
<div class="span10 well">
<h3>frame</h3>
<iframe id="f1" src="inner.html" width="800",
height="600"></iframe>
</div>
</div>
</body>
<script
src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.
min.js"></script>
</html>
inner.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>inner</title>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>inner</h3>
<iframe id="f2" src="http://www.baidu.com"
width="700"height="500"></iframe>
<a href="javascript:alert('watir-webdriver betterthan
selenium webdriver;')">click</a>
</div>
</div>
</body>
</html>
frame.html 中嵌套 inner.html ,兩個文件和我們的腳本文件放同一個目錄下,通過
博客園 — 蟲師
http://fnng.cnblogs.com 34
瀏覽器打開,得到下列頁面:
下面通過 switch_to_frame() 方法來進行定位:
#coding=utf-8
fromselenium import webdriver
import time
import os
browser =webdriver.Firefox()
file_path= 'file:///' + os.path.abspath('frame.html')
browser.get(file_path)
browser.implicitly_wait(30)
#先找到到 ifrome1(id = f1)
browser.switch_to_frame("f1")
#再找到其下面的 ifrome2(id =f2)
browser.switch_to_frame("f2")
#下面就可以正常的操作元素了
博客園 — 蟲師
http://fnng.cnblogs.com 35
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3)
browser.quit()
12.2 、多層窗口定位
有可能嵌套的不是框架,而是窗口,還有真對窗口的方法:switch_to_window
用法與 switch_to_frame 相同:
driver.switch_to_window("windowName")
十三、層級定位
假如兩個控件,他們長的一模樣,還都叫“張三”,唯一的不同是一個在北京,一
個在上海,那我們就可以通過,他們的城市,區,街道,來找到他們。
在實際的測試中也經常會遇到這種問題:頁面上有很多個屬性基本相同的元素,現
在需要具體定位到其中的一個。由於屬性基本相當,所以在定位的時候會有些麻煩,這
時候就需要用到層級定位。先定位父元素,然后再通過父元素定位子孫元素。
level_locate.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Level Locate</title>
<script type="text/javascript" async=""
src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></scri
pt>
<link
href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-c
ombined.min.css" rel="stylesheet" />
</head>
<body>
博客園 — 蟲師
http://fnng.cnblogs.com 36
<h3>Levellocate</h3>
<divclass="span3">
<divclass="well">
<divclass="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown"
href="#">Link1</a>
<ul class="dropdown-menu" role="menu"
aria-labelledby="dLabel"id="dropdown1">
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something elsehere</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#">Separatedlink</a></li>
</ul>
</div>
</div>
</div>
<divclass="span3">
<divclass="well">
<divclass="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown"
href="#">Link2</a>
<ul class="dropdown-menu" role="menu"
aria-labelledby="dLabel">
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something elsehere</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#">Separatedlink</a></li>
</ul>
</div>
</div>
</div>
</body>
<script
src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min
.js"></script>
</html>
上面的 html 代碼比較亂,請復制到編輯器中查看,如 nodepad ++ 編輯器。
(注意,這個頁面需要和我們的自動化腳本放在同一個目錄下)通過瀏覽器打開:
博客園 — 蟲師
http://fnng.cnblogs.com 37
定位思路:
具體思路是:先點擊顯示出1個下拉菜單,然后再定位到該下拉菜單所在的 ul,再
定位這個 ul 下的某個具體的 link。在這里,我們定位第1個下拉菜單中的 Action 這個
選項。
腳本如下:
# -*- coding: utf-8-*-
fromselenium import webdriver
fromselenium.webdriver.support.uiimport WebDriverWait
import time
import os
dr =webdriver.Firefox()
file_path= 'file:///' + os.path.abspath('level_locate.html')
dr.get(file_path)
#點擊 Link1鏈接(彈出下拉列表)
dr.find_element_by_link_text('Link1').click()
#找到 id 為 dropdown1的父元素
WebDriverWait(dr, 10).until(lambda the_driver:
the_driver.find_element_by_id('dropdown1').is_displayed())
#在父親元件下找到 link 為 Action 的子元素
menu = dr.find_element_by_id('dropdown1').find_element_by_link_text('Action')
#鼠標定位到子元素上
webdriver.ActionChains(dr).move_to_element(menu).perform()
time.sleep(2)
博客園 — 蟲師
http://fnng.cnblogs.com 38
dr.quit()
WebDriverWait(dr, 10)
10秒內每隔500毫秒掃描1次頁面變化,當出現指定的元素后結束。dr 就不解釋了,前
面操作 webdriver.firefox()的句柄
is_displayed()
該元素是否用戶可以見
class ActionChains(driver)
driver: 執行用戶操作實例 webdriver
生成用戶的行為。所有的行動都存儲在 actionchains 對象。通過 perform()存儲的行為。
move_to_element(menu)
移動鼠標到一個元素中,menu 上面已經定義了他所指向的哪一個元素
to_element:元件移動到
perform()
執行所有存儲的行為
十四、上傳文件操作
文件上傳操作也比較常見功能之一,上傳功能沒有用到新有方法或函數,關鍵是思
路。
上傳過程一般要打開一個本地窗口,從窗口選擇本地文件添加。所以,一般會卡在
如何操作本地窗口添加上傳文件。
其實,在 selenium webdriver 沒我們想的那么復雜;只要定位上傳按鈕,通
send_keys 添加本地文件路徑就可以了。絕對路徑和相對路徑都可以,關鍵是上傳的文
件存在。下面通地例子演示。
博客園 — 蟲師
http://fnng.cnblogs.com 39
14.1 、操作文件上傳例子
upload_file.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>upload_file</title>
<script type="text/javascript"
async=""src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
"></script>
<link
href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstra
p-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
</script>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>upload_file</h3>
<input type="file" name="file" />
</div>
</div>
</body>
<script
src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.
min.js"></script>
</html>
通過瀏覽器打開,得到下列頁面:
操作上傳腳本:
#coding=utf-8
from selenium import webdriver
博客園 — 蟲師
http://fnng.cnblogs.com 40
import os,time
driver = webdriver.Firefox()
#腳本要與 upload_file.html 同一目錄
file_path= 'file:///' + os.path.abspath('upload_file.html')
driver.get(file_path)
#定位上傳按鈕,添加本地文件
driver.find_element_by_name("file").send_keys('D:\\selenium_use_c
ase\upload_file.txt')
time.sleep(2)
driver.quit()
14.2 、139 郵箱上傳
其它有些應用不好找,所以就自己創建頁面,這樣雖然麻煩,但腳本代碼突出重點。
這里找一139郵箱的實例,有帳號的同學可以測試一下~!
(登陸基礎版的139郵箱,網盤模塊上傳文件)
#coding=utf-8
fromselenium import webdriver
import os,time
driver = webdriver.Firefox()
driver.get("http://m.mail.10086.cn")
driver.implicitly_wait(30)
#登陸
driver.find_element_by_id("ur").send_keys("手機號")
driver.find_element_by_id("pw").send_keys("密碼")
driver.find_element_by_class_name("loading_btn").click()
time.sleep(3)
#進入139網盤模塊
driver.find_element_by_xpath("/html/body/div[3]/a[9]/span[2]").click()
博客園 — 蟲師
http://fnng.cnblogs.com 41
time.sleep(3)
#上傳文件
driver.find_element_by_id("id_file").send_keys('D:\\selenium_use_case\upload
_file.txt')
time.sleep(5)
driver.quit()
十五、下拉框處理
本節重點
處理下拉框
switch_to_alert()
accept()
下拉框是我們最常見的一種頁面元素,對於一般的元素,我們只需要一次就定位,但下
拉框里的內容需要進行兩次定位,先定位到下拉框,再定位到下拉框內里的選項。
15.1 、操作下拉框例子
drop_down.html
<html>
<body>
<select id="ShippingMethod"
onchange="updateShipping(options[selectedIndex]);" name="ShippingMethod">
<option value="12.51">UPS Next Day Air ==> $12.51</option>
<option value="11.61">UPS Next Day Air Saver ==> $11.61</option>
<option value="10.69">UPS 3 Day Select ==> $10.69</option>
<option value="9.03">UPS 2nd Day Air ==> $9.03</option>
<option value="8.34">UPS Ground ==> $8.34</option>
<option value="9.25">USPS Priority Mail Insured ==> $9.25</option>
<option value="7.45">USPS Priority Mail ==> $7.45</option>
<option value="3.20" selected="">USPS First Class ==> $3.20</option>
博客園 — 蟲師
http://fnng.cnblogs.com 42
</select>
</body>
</html>
保存並通過瀏覽器打開,如下:
現在我們來通過腳本選擇下拉列表里的 $10.69
#-*-coding=utf-8
fromselenium import webdriver
import os,time
driver= webdriver.Firefox()
file_path= 'file:///' + os.path.abspath('drop_down.html')
driver.get(file_path)
time.sleep(2)
#先定位到下拉框
m=driver.find_element_by_id("ShippingMethod")
#再點擊下拉框下的選項
m.find_element_by_xpath("//option[@value='10.69']").click()
time.sleep(3)
driver.quit()
解析:
這里可能和之前的操作有所不同,首先要定位到下拉框的元素,然后選擇下拉列表
中的選項進行點擊操作。
m=driver.find_element_by_id("ShippingMethod")
m.find_element_by_xpath("//option[@value='10.69']").click()
博客園 — 蟲師
http://fnng.cnblogs.com 43
15.2 、百度搜索設置下拉框操作
#-*-coding=utf-8
fromselenium import webdriver
import os,time
driver= webdriver.Firefox()
driver.get("http://www.baidu.com")
#進入搜索設置頁
driver.find_element_by_link_text("搜索設置").click()
#設置每頁搜索結果為100條
m=driver.find_element_by_name("NR")
m.find_element_by_xpath("//option[@value='100']").click()
time.sleep(2)
#保存設置的信息
driver.find_element_by_xpath("//input[@value='保存設置']").click()
time.sleep(2)
driver.switch_to_alert().accept()
#跳轉到百度首頁后,進行搜索表(一頁應該顯示100條結果)
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
time.sleep(3)
driver.quit()
解析:
當我們在保存百度的設置時會會彈出一個確定按鈕;我們並沒按照常規的方法去定
位彈窗上的“確定”按鈕,而是使用:
driver.switch_to_alert().accept()
完成了操作,這是因為彈窗比較是一個具有唯一性的警告信息,所以可以用這種簡便
的方法處理。
– switch_to_alert()
博客園 — 蟲師
http://fnng.cnblogs.com 44
焦點集中到頁面上的一個警告(提示)
– accept()
接受警告提示
十六、alert 、confirm 、prompt 的處理
本節重點:
text 返回 alert/confirm/prompt 中的文字信息
accept 點擊確認按鈕
dismiss 點擊取消按鈕,如果有的話
send_keys 輸入值,這個 alert\confirm 沒有對話框就不能用了,不然會報錯。
在實際的應用中,我們會碰到各種交互的彈窗,在上面百度搜索設置的例子中,我們用
switch_to_alert() 處理警告框非常簡單;其實,對於原生的 js alert 、confirm 以及 prompt
都可以通過 webdriver 的 switch_to_alert()方法進行處理。
比較常見下的就是下面這種類型的確認框:
selenium.webdriver.remote.webdriver.switch_to_alert()
將焦點切換到頁面上的警報
博客園 — 蟲師
http://fnng.cnblogs.com 45
Usage:
driver.switch_to_alert()
由於用法簡單,這里就不給具體例子了,在實際應用中:
#接受警告信息
alert = driver.switch_to_alert()
alert.accept()
#得到文本信息打印
alert = driver.switch_to_alert()
print alert.text()
#取消對話框(如果有的話)
alert = driver.switch_to_alert()
alert.dismiss()
#輸入值
alert = driver.switch_to_alert()
alert.send_keys(“xxx”)
十七、 對話框的處理
本節重點:
打開對話框
關閉對話框
操作對話框中的元素
current_window_handle 獲得當前窗口
window_handles 獲得所有窗口
更多的時候我們在實際的應用中碰到的並不是簡單警告框,而是提供更多功能的會話
框。
17.1 、div 對話框的處理
modal.html
博客園 — 蟲師
http://fnng.cnblogs.com 46
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>modal</title>
<script type="text/javascript" async=""
src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link
href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css"
rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#click').click(function(){
$(this).parent().find('p').text('Click on the link to success!');
});
});
</script>
</head>
<body>
<h3>modal</h3>
<div class="row-fluid">
<div class="span6">
<!-- Button to trigger modal -->
<a href="#myModal" role="button" class="btn btn-primary"
data-toggle="modal" id="show_modal">Click</a>
<!-- Modal -->
<div id="myModal" class="modal hide fade" tabindex="-1"
role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×</button>
<h3 id="myModalLabel">Modal header</h3>
</div>
<div class="modal-body">
<p>Congratulations, you open the window!</p>
<a href="#" id="click">click me</a>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal"
aria-hidden="true">Close</button>
<button class="btn btn-primary">Save changes</button>
</div>
</div>
博客園 — 蟲師
http://fnng.cnblogs.com 47
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>modal</title>
<script type="text/javascript" async=""
src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link
href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css"
rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#click').click(function(){
$(this).parent().find('p').text('Click on the link to success!');
});
});
</script>
</head>
<body>
<h3>modal</h3>
<div class="row-fluid">
<div class="span6">
<!-- Button to trigger modal -->
<a href="#myModal" role="button" class="btn btn-primary"
data-toggle="modal" id="show_modal">Click</a>
<!-- Modal -->
<div id="myModal" class="modal hide fade" tabindex="-1"
role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×</button>
<h3 id="myModalLabel">Modal header</h3>
</div>
<div class="modal-body">
<p>Congratulations, you open the window!</p>
<a href="#" id="click">click me</a>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal"
aria-hidden="true">Close</button>
<button class="btn btn-primary">Save changes</button>
</div>
</div>
博客園 — 蟲師
http://fnng.cnblogs.com 48
</div>
</div>
</body>
<script
src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
代碼有點長,你可以直接賦值粘貼到 Notepad++中,保存成 html 通過瀏覽器打開,效
果如下:
操作腳本如下:
# -*- coding: utf-8-*-
fromselenium import webdriver
fromtimeimport sleep
import os
import selenium.webdriver.support.ui asui
if 'HTTP_PROXY'in os.environ:del os.environ['HTTP_PROXY']
dr =webdriver.Firefox()
file_path= 'file:///' +os.path.abspath('modal.html')
dr.get(file_path)
# 打開對話框
dr.find_element_by_id('show_modal').click()
sleep(3)
# 點擊對話框中的鏈接
博客園 — 蟲師
http://fnng.cnblogs.com 49
# 由於對話框中的元素被蒙板所遮擋,直接點擊會報 Element is not clickable 的錯誤
# 所以使用 js 來模擬 click
link= dr.find_element_by_id('myModal').find_element_by_id('click')
dr.execute_script('$(arguments[0]).click()',link)
sleep(4)
# 關閉對話框
buttons =
dr.find_element_by_class_name('modal-footer').find_elements_by_tag_name('but
ton')
buttons[0].click()
dr.quit()
17.2 、一般對話框的處理
有些彈出對話框窗,我們可以通過判斷是否為當前窗口的方式進行操作。
#獲得當前窗口
nowhandle=driver.current_window_handle
#打開彈窗
driver.find_element_by_name("xxx").click()
#獲得所有窗口
allhandles=driver.window_handles
for handle in allhandles:
if handle!=nowhandle: #比較當前窗口是不是原先的窗口
driver.switch_to_window(handle) #獲得當前窗口的句柄
dirver.find_element_by_class_name("xxxx").click() #在當前窗口操作
博客園 — 蟲師
http://fnng.cnblogs.com 50
#回到原先的窗口
driver.switch_to_window(nowhandle)
這里只是操作窗口的代碼片段,提供一個思路,能否完成我們想要的結果,還需要我們
通過實例去驗證。
十八、調用 js
本節重點:
調用 js 方法
execute_script(script, *args)
在當前窗口/框架 同步執行 javaScript
script:JavaScript 的執行。
*args:適用任何 JavaScript 腳本。
使用:
driver.execute_script(‘document.title’)
18.1 、通過 js 隱藏元素
js.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>js</title>
<script type="text/javascript" async=""
src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></s
cript>
<link
博客園 — 蟲師
http://fnng.cnblogs.com 51
href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstra
p-combined.min.css" rel="stylesheet" />
<script type="text/javascript"> $(document).ready(function(){
$('#tooltip').tooltip({"placement": "right"});
});
</script>
</head>
<body>
<h3>js</h3>
<div class="row-fluid">
<div class="span6 well">
<a id="tooltip" href="#" data-toggle="tooltip" title="
selenium-webdriver(python)">hover to see tooltip</a>
<a class="btn">Button</a>
</div>
</div>
</body>
<script
src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.
min.js"></script>
</html>
(保持 html 文件與執行腳本在同一目錄下)
保存並通過瀏覽器打開,如下:
執行 js 一般有兩種場景:
一種是在頁面上直接執行 JS
另一種是在某個已經定位的元素上執行 JS
#coding=utf-8
fromselenium import webdriver
import time,os
博客園 — 蟲師
http://fnng.cnblogs.com 52
driver = webdriver.Firefox()
file_path= 'file:///' + os.path.abspath('js.html')
driver.get(file_path)
#######通過 JS 隱藏選中的元素##########第一種方法:
driver.execute_script('$("#tooltip").fadeOut();')
time.sleep(5)
#第二種方法:
button = driver.find_element_by_class_name('btn')
driver.execute_script('$(arguments[0]).fadeOut()',button)
time.sleep(5)
driver.quit()
18.2 、通過 js 使輸入框標紅
#coding=utf-8
fromselenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fvod.kuai
bo.com%2F%3Ft%3Dhome")
#給用戶名的輸入框標紅
js="var q=document.getElementById(\"user_name\");q.style.border=\"1px solid
red\";"
#調用 js
driver.execute_script(js)
time.sleep(3)
driver.find_element_by_id("user_name").send_keys("username")
driver.find_element_by_id("user_pwd").send_keys("password")
driver.find_element_by_id("dl_an_submit").click()
博客園 — 蟲師
http://fnng.cnblogs.com 53
time.sleep(3)
driver.quit()
js 解釋:
q=document.getElementById(\"user_name\")
元素 q的 id 為 user_name
q.style.border=\"1px solid red\
元素 q的樣式,邊框為1個像素紅色
十九、控制瀏覽器滾動條
有時候我們需要控制頁面滾動條上的滾動條,但滾動條並非頁面上的元素,這個時
候就需要借助 js 是來進行操作。一般用到操作滾動條的會兩個場景:
注冊時的法律條文需要閱讀,判斷用戶是否閱讀的標准是:滾動條是否拉到最
下方。
要操作的頁面元素不在吸視范圍,無法進行操作,需要拖動滾動條
其實,實現這個功能只要一行代碼,但由於不懂 js ,所以花了不小力氣找到這種方法。
用於標識滾動條位置的代碼
<body onload= "document.body.scrollTop=0">
<body onload= "document.body.scrollTop=100000">
如果滾動條在最上方的話,scrollTop=0,那么要想使用滾動條在最可下方,可以
scrollTop=100000 ,這樣就可以使滾動條在最下方。
博客園 — 蟲師
http://fnng.cnblogs.com 54
19.1 、場景一
先來解決場第一個問題,法律條款是一個內嵌窗口,通過 firebug 工具可以定位到內嵌
入窗口可以定位到元素的 id ,可以通過下面的代碼實現。
js="var q=document.getElementById('id').scrollTop=10000"
driver.execute_script(js)
19.2 、場景二
有滾動條的頁面到處可見,這個就比較容易找例子,我們以操作百度搜索結果頁為例:
#coding=utf-8
fromselenium import webdriver
import time
#訪問百度
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()
time.sleep(3)
#將頁面滾動條拖到底部
js="var q=document.documentElement.scrollTop=10000"driver.execute_script(js)
time.sleep(3)
#將滾動條移動到頁面的頂部
js="var q=document.documentElement.scrollTop=0"driver.execute_script(js)
time.sleep(3)
driver.quit()
博客園 — 蟲師
http://fnng.cnblogs.com 55
二十、cookie 處理
本節重點:
driver.get_cookies() 獲得 cookie 信息
add_cookie(cookie_dict) 向 cookie 添加會話信息
delete_cookie(name) 刪除特定(部分)的 cookie
delete_all_cookies() 刪除所有 cookie
通過 webdriver 操作 cookie是一件非常有意思的事兒,有時候我們需要了解瀏覽器中
是否存在了某個 cookie 信息,webdriver 可以幫助我們讀取、添加,刪除 cookie 信息。
20.1 、打印 cookie 信息
#coding=utf-8
fromselenium import webdriver
import time
driver = webdriver.Chrome()
driver.get("http://www.youdao.com")
# 獲得 cookie 信息
cookie= driver.get_cookies()
#將獲得 cookie 的信息打印
print cookie
driver.quit()
運行打印信息:
[{u'domain': u'.youdao.com', u'secure': False, u'value':
u'aGFzbG9nZ2VkPXRydWU=', u'expiry': 1408430390.991375, u'path': u'/',
u'name': u'_PREF_ANONYUSER__MYTH'}, {u'domain': u'.youdao.com', u'secure':
False, u'value': u'1777851312@218.17.158.115', u'expiry': 2322974390.991376,
u'path': u'/', u'name': u'OUTFOX_SEARCH_USER_ID'}, {u'path': u'/', u'domain':
u'www.youdao.com', u'name': u'JSESSIONID', u'value':
博客園 — 蟲師
http://fnng.cnblogs.com 56
u'abcUX9zdw0minadIhtvcu', u'secure': False}]
20.2 、對 cookie 操作
上面的方式打印了所有 cookie 信息,太多太亂,我們只想有真對性的打印自己想要
的信息,看下面的例子
#coding=utf-8
fromselenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://www.youdao.com")
#向 cookie 的 name 和 value 添加會話信息。
driver.add_cookie({'name':'key-aaaaaaa', 'value':'value-bbbb'})
#遍歷 cookies 中的 name 和 value 信息打印,當然還有上面添加的信息
for cookie in driver.get_cookies():
print "%s-> %s" % (cookie['name'], cookie['value'])
# 下面可以通過兩種方式刪除 cookie# 刪除一個特定的 cookie
driver.delete_cookie("CookieName")
# 刪除所有 cookie
driver.delete_all_cookies()
time.sleep(2)
driver.close()
運行打印信息:
YOUDAO_MOBILE_ACCESS_TYPE -> 1
_PREF_ANONYUSER__MYTH ->aGFzbG9nZ2VkPXRydWU=
OUTFOX_SEARCH_USER_ID ->-1046383847@218.17.158.115
JSESSIONID -> abc7qSE_SBGsVgnVLBvcu
key-aaaaaaa ->value-bbbb # 這一條是我們自己添加的
博客園 — 蟲師
http://fnng.cnblogs.com 57
20.3 、博客園登陸分析cookie
通過博客園登陸來分析 cookie
#coding=utf-8
fromselenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://passport.cnblogs.com/login.aspx?ReturnUrl=http://www.cnbl
ogs.com/fnng/admin/EditPosts.aspx")
time.sleep(3)
driver.maximize_window()# 瀏覽器全屏顯示
#通過用戶名密碼登陸
driver.find_element_by_id("tbUserName").send_keys("fnngj")
driver.find_element_by_id("tbPassword").send_keys("123456")
#勾選保存密碼
driver.find_element_by_id("chkRemember").click()
time.sleep(3)
#點擊登陸按鈕
driver.find_element_by_id("btnLogin").click()
#獲取 cookie 信息並打印
cookie= driver.get_cookies()
print cookie
time.sleep(2)
driver.close()
運行打印信息:
#第一次執行信息
>>>
[{u'domain': u'.cnblogs.com', u'name': u'.DottextCookie', u'value':
u'C709F15A8BC0B3E8D9AD1F68B371053849F7FEE31F73F1292A150932FF09A7B0D4A1B449A3
2A6B24AD986CDB05B9998471A37F39C3B637E85E481AA986D3F8C187D7708028F9D4ED3B326B
46DC43B416C47B84D706099ED1D78B6A0FC72DCF948DB9D5CBF99D7848FDB78324',
博客園 — 蟲師
http://fnng.cnblogs.com 58
u'expiry': None, u'path': u'/', u'secure': False}]
>>> =========================RESTART ================================
#第二次執行信息
>>>
[{u'domain': u'.cnblogs.com', u'name': u'.DottextCookie', u'value':
u'5BB735CAD62E99F8CCB9331C32724E2975A0150D199F4243AD19357B3F99A416A93B2E803F
4D5C9D065429713BE8B5DB4ED760EDCBAF492EABE2158B3A6FBBEA2B95C4DA3D2EFEADACC324
7040906F1462731F652199E2A8BEFD8A9B6AAE87CF3059A3CAEB9AB0D8B1B7AD2A',
u'expiry': 1379502502, u'path': u'/', u'secure': False}]
>>>
第一次注釋掉勾選保存密碼的操作,第二次通過勾選保存密碼獲得 cookie 信息 ;
來看兩次運行結果的 cookie 的何不同:
u'expiry': None
u'expiry': 1379502502
通過對比發現,不勾選保存密碼時 expiry 的值為 none ; 那么就可以初步判斷勾選
保存密碼的操作在 cookie 中起到了作用。至於是否准確可以再做進一步的分析。
二十一、webdriver 原理解析
之前看乙醇視頻中提到,selenium 的 ruby 實現有一個小后門,在代碼前加上
$DEBUG=1 ,再運行腳本的過程中,就可以看到客戶端請求的信息與服務器端返回的數據;
覺得這個功能很強大,可以幫助理解 webdriver 的運行原理。
后來查了半天,python 並沒有提供這樣一個方便的后門,不過我們可以通過代理的方式
獲得這些交互信息;
一、需要安裝 java 虛擬機與 selenium-server-standalone ,參考本文檔第一章環境搭
建第7、8步操作。
二、通過下面命令啟動服務:
C:\selenium>java -jar selenium-server-standalone-2.33.0.jar
在命令結尾加 >d:\log.txt 可以將命令信息存入文件,但信息很少。
運行下面的自動化腳本:
博客園 — 蟲師
http://fnng.cnblogs.com 59
#coding =utf-8
import time
fromselenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
driver = webdriver.Remote(desired_capabilities=DesiredCapabilities.CHROME)
driver.get("http://www.youdao.com")
driver.find_element_by_name("q").send_keys("hello")
driver.find_element_by_name("q").send_keys("key.ENTER")
driver.close()
webdriver 原理:
1. WebDriver 啟動目標瀏覽器,並綁定到指定端口。該啟動的瀏覽器實例,做為 web driver
的 remote server。
2. Client 端通過 CommandExcuter 發送 HTTPRequest 給 remote server 的偵聽端口(通信
協議: the webriver wire protocol)
3. Remote server 需要依賴原生的瀏覽器組件(如:IEDriver.dll,chromedriver.exe),來轉
化轉化瀏覽器的 native 調用。
查看命令提示符下的運行日志:
咋一看很亂,慢慢分析一下就發現很有意思!結合上面的腳本分析
------------------------------------------------------------------------啟動代理進入監聽狀態
C:\selenium>java -jarselenium-server-standalone-2.33.0.jar
八月 22, 201310:19:48 上午org.openqa.grid.selenium.GridLaunchermain
INFO:Launchingastandalone server
10:19:48.734 INFO-Java:Oracle Corporation 23.21-b01
10:19:48.734 INFO-OS:WindowsXP 5.1 x86
10:19:48.734 INFO-v2.33.0, withCore v2.33.0.Builtfrom revision4e90c97
10:19:48.843INFO - RemoteWebDriver instances shouldconnectto:http://127.0.0.
1:4444/wd/hub
10:19:48.843 INFO-VersionJetty/5.1.x
10:19:48.843 INFO-StartedHttpContext[/selenium-server/driver,/selenium-server
/driver]
博客園 — 蟲師
http://fnng.cnblogs.com 60
10:19:48.843 INFO-StartedHttpContext[/selenium-server,/selenium-server]
10:19:48.843 INFO-StartedHttpContext[/,/]
10:19:48.890 INFO-Startedorg.openqa.jetty.jetty.servlet.ServletHandler@176343e
10:19:48.890 INFO-StartedHttpContext[/wd,/wd]
10:19:48.906INFO - Started SocketListeneron 0.0.0.0:4444
10:19:48.906 INFO-Startedorg.openqa.jetty.jetty.Server@388c74
--------------------------------------------------------------------------------------
創建新 session
10:20:38.593 INFO-Executing: [newsession: {platform=ANY,javascriptEnabled=tr
ue,browserName=chrome,version=}] atURL: /session)
10:20:38.593 INFO-Creating a new session for Capabilities[{platform=ANY,java
scriptEnabled=true,browserName=chrome,version=}]
webdrivr 通過 GET 方式發送請求
[0.921][INFO]: receivedWebriver request:GET/status
向 webdrver 返回響應,返回碼200表示成功
[0.921][INFO]: sending Webriverresponse:200{
"sessionId":"",
"status": 0,
"value":{
"build": {
"version":"alpha" },
"os":{
"arch": "x86",
"name": "WindowsNT",
"version":"5.1 SP3" }
}
}
webdriver再次以 POST 方式發送請求,並啟動瀏覽器相關信息
[0.984][INFO]: receivedWebriver request:POST /session{
"desiredCapabilities":{
"browserName": "chrome",
"javascriptEnabled": true,
"platform":"ANY",
"version": "" }
博客園 — 蟲師
http://fnng.cnblogs.com 61
}
[0.984][INFO]:Launchingchrome:"C:\ocuments and Settings\Administrator\LocalS
ettings\Application ata\Google\Chrome\Application\chrome.exe" --remote-debugging
-port=4223--no-first-run --enable-logging--logging-level=1--user-data-dir="C:
\OCUME~1\AMINI~1\LOCALS~1\Temp\scoped_dir1808_7550"
--load-extension="C:\OCUME~1\AMINI~1\LOCALS~1\Temp\scoped_dir1808_26821\internal"
--ignore-certificate-error
sdata:text/html;charset=utf-8,
[1.773][INFO]: sending Webriverresponse:303
webdriver 再次以GET 方法請求,這附加上了session 的信息
[1.778][INFO]: receivedWebriver request:GET/session/32b33aa585ccbbf7ba7853588
2852af3
服務器先對 sesssionID 進行解析,確認是 selenium調用的以及要訪問的網址,
[1.779][INFO]: sending Webriverresponse:200{
"sessionId":"32b33aa585ccbbf7ba78535882852af3",
"status": 0,
"value":{
"acceptSslCerts":true,
"applicationCacheEnabled": false,
"browserConnectionEnabled":false,
"browserName": "chrome",
"chrome":{
"chromedriverVersion":"2.0" },
"cssSelectorsEnabled": true,
"databaseEnabled": true,
"handlesAlerts": true,
"javascriptEnabled": true,
"locationContextEnabled":true,
"nativeEvents":true,
"platform":"Windows NT",
"rotatable": false,
"takesScreenshot": true,
"version": "27.0.1453.116",
"webStorageEnabled": true }
}
10:20:40.640 INFO-Done:/session
博客園 — 蟲師
http://fnng.cnblogs.com 62
10:20:40.640 INFO-Executing: org.openqa.selenium.remote.server.handler.GetSess
ionCapabilities@14cf7a1at URL:/session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc)
10:20:40.640 INFO-Done:/session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc
10:20:40.656INFO - Executing:[get:http://www.youdao.com] atURL: /session/ac5
b2c71-5b1a-469e-814c-fdd09a2061fc/url)
webdriver 正試向服務器請求youdao 網站
[1.820][INFO]: receivedWebriver request:POST /session/32b33aa585ccbbf7ba785358
82852af3/url {
"url":"http://www.youdao.com"}
[1.822][INFO]: waiting for pending navigations...
[1.829][INFO]: donewaitingforpendingnavigations
[2.073][INFO]: waiting for pending navigations...
[2.900][INFO]: donewaitingforpendingnavigations
獲得服務器數據的應答
[2.900][INFO]: sending Webriverresponse:200{
"sessionId":"32b33aa585ccbbf7ba78535882852af3",
"status": 0,
"value":null}
10:20:41.734 INFO-Done:/session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/url
--------------------------------------------------------------下面接着發送定位輸入框的信息
10:20:41.734 INFO-Executing: [find element:By.name: q]at URL:/session/ac5b2
c71-5b1a-469e-814c-fdd09a2061fc/element)
[2.905][INFO]: receivedWebriver request:POST /session/32b33aa585ccbbf7ba785358
82852af3/element {
"using":"name",
"value":"q"}
[2.905][INFO]: waiting for pending navigations...
[2.905][INFO]: donewaitingforpendingnavigations
[2.922][INFO]: waiting for pending navigations...
[2.922][INFO]: donewaitingforpendingnavigations
得到服務器應答
[2.922][INFO]: sending Webriverresponse:200{
"sessionId":"32b33aa585ccbbf7ba78535882852af3",
博客園 — 蟲師
http://fnng.cnblogs.com 63
"status": 0,
"value":{
"ELEMENT": "0.19427558477036655:1" }
}
10:20:41.765 INFO-Done:/session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element
10:20:41.765 INFO-Executing: [send keys: 0 org.openqa.selenium.support.events.
EventFiringWebDriver$EventFiringWebElement@a8215ba9, [h, e,l, l,o]]at URL:/s
ession/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element/0/value)
向定位到的輸入框寫入 hello
[2.936][INFO]: receivedWebriver request:POST /session/32b33aa585ccbbf7ba785358
82852af3/element/0.19427558477036655:1/value {
"id": "0.19427558477036655:1",
"value":["h", "e","l", "l","o"]
}
[2.936][INFO]: waiting for pending navigations...
[2.936][INFO]: donewaitingforpendingnavigations
[3.002][INFO]: waiting for pending navigations...
[3.002][INFO]: donewaitingforpendingnavigations
[3.002][INFO]: sending Webriverresponse:200{
"sessionId":"32b33aa585ccbbf7ba78535882852af3",
"status": 0,
"value":null}
10:20:41.843INFO - Done: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element/
0/value
再次發送定位輸入框的請求
10:20:41.843 INFO-Executing: [find element:By.name: q]at URL:/session/ac5b2
c71-5b1a-469e-814c-fdd09a2061fc/element)
[3.006][INFO]: receivedWebriver request:POST /session/32b33aa585ccbbf7ba785358
82852af3/element {
"using":"name",
"value":"q"}
[3.006][INFO]: waiting for pending navigations...
[3.006][INFO]: donewaitingforpendingnavigations
[3.016][INFO]: waiting for pending navigations...
博客園 — 蟲師
http://fnng.cnblogs.com 64
[3.016][INFO]: donewaitingforpendingnavigations
[3.016][INFO]: sending Webriverresponse:200{
"sessionId":"32b33aa585ccbbf7ba78535882852af3",
"status": 0,
"value":{
"ELEMENT": "0.19427558477036655:1" }
}
10:20:41.859 INFO-Done:/session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element
10:20:41.859 INFO-Executing: [send keys: 0 org.openqa.selenium.support.events.
EventFiringWebDriver$EventFiringWebElement@a8215ba9, [k, e,y, .,E, N,T, E,R]
]at URL:/session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element/0/value)
對定位的到的輸入框發送回車(ENTER)事件請求
[3.021][INFO]: receivedWebriver request:POST /session/32b33aa585ccbbf7ba785358
82852af3/element/0.19427558477036655:1/value {
"id": "0.19427558477036655:1",
"value":["k", "e","y", ".","E", "N","T", "E","R"]
}
[3.021][INFO]: waiting for pending navigations...
[3.021][INFO]: donewaitingforpendingnavigations
[3.064][INFO]: waiting for pending navigations...
[3.064][INFO]: donewaitingforpendingnavigations
[3.064][INFO]: sending Webriverresponse:200{
"sessionId":"32b33aa585ccbbf7ba78535882852af3",
"status": 0,
"value":null}
10:20:41.906INFO - Done: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/element/
0/value
10:20:41.906 INFO - Executing: [close window] at URL:
/session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/window)
[3.068][INFO]: receivedWebriver request:ELETE/session/32b33aa585ccbbf7ba78535
882852af3/window
[WARNING:chrome_desktop_impl.cc(88)] chromedetaches,user shouldtake careof d
irectory:C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\scoped_dir1808_7550andC:\DOCUME~1\
ADMINI~1\LOCALS~1\Temp\scoped_dir1808_26821
[5.318][INFO]: sending Webriverresponse:200{
博客園 — 蟲師
http://fnng.cnblogs.com 65
"sessionId":"32b33aa585ccbbf7ba78535882852af3",
"status": 0,
"value":null}
10:20:44.156INFO - Done: /session/ac5b2c71-5b1a-469e-814c-fdd09a2061fc/window
第二部分:框架的力量
博客園 — 蟲師
http://fnng.cnblogs.com 66
二十二、引入 unittest 框架
unittest 框架學習
借助 IED 錄制腳本,
博客園 — 蟲師
http://fnng.cnblogs.com 67
將腳本導出,保存為 baidu.py ,通過 python IDLE 編輯器打開。如下:
fromselenium import webdriver
fromselenium.webdriver.common.by import By
fromselenium.webdriver.common.keys import Keys
fromselenium.webdriver.support.uiimport Select
fromselenium.common.exceptions import NoSuchElementException
import unittest, time, re
class Baidu(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/" self.verificationErrors =
[]
self.accept_next_alert =True
def test_baidu(self):
driver = self.driver
driver.get(self.base_url+ "/")
driver.find_element_by_id("kw").send_keys("selenium webdriver")
driver.find_element_by_id("su").click()
driver.close()
def is_element_present(self, how, what):
博客園 — 蟲師
http://fnng.cnblogs.com 68
try:self.driver.find_element(by=how, value=what)
except NoSuchElementException, e: return False
return True
def is_alert_present(self):
try:self.driver.switch_to_alert()
except NoAlertPresentException, e:return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ =="__main__":
unittest.main()
加入 unittest 框架后,看上去比我們之前見的腳本復雜了很多,除了中間操作瀏覽器的幾行,
其它都看不懂,不要急,我們來分析一下~!
import unittest
相想使用 unittest 框架,首先要引入 unittest 包,這個不多解釋。
class Baidu(unittest.TestCase):
Baidu 類繼承 unittest.TestCase 類,從 TestCase 類繼承是告訴 unittest 模塊的方式,
這是一個測試案例。
def setUp(self):
self.driver = webdriver.Firefox()
博客園 — 蟲師
http://fnng.cnblogs.com 69
self.base_url = "http://www.baidu.com/"
setUp 用於設置初始化的部分,在測試用例執行前,這個方法中的函數將先被調用。
這里將瀏覽器的調用和 URL 的訪問放到初始化部分。
self. verificationErrors =[]
腳本運行時,錯誤的信息將被打印到這個列表中。
self.accept_next_alert =True
是否繼續接受下一下警告(字面意思,沒找到解釋!)
def test_baidu(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw" ).send_keys( "selenium webdriver")
driver.find_element_by_id("su" ).click()
test_baidu 中放置的就是我們的測試腳本了,這部分我們並不陌生;因為我們執行的
腳本就在這里。
def is_element_present(self, how, what):
try : self.driver.find_element(by=how, value= what)
except NoSuchElementException, e: return False
return True
is_element_present 函數用來查找頁面元素是否存在,在這里用處不大,通常刪除。
因為判斷頁面元素是否存在一般都加在 testcase 中。
def is_alert_present(self):
try:self.driver.switch_to_alert()
except NoAlertPresentException,e: return False
return True
對彈窗異常的處理
def close_alert_and_get_its_text(self):
try:
博客園 — 蟲師
http://fnng.cnblogs.com 70
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
returnalert_text
finally :self.accept_next_alert =True
關閉警告和對得到文本框的處理,如果不熟悉 python 的異常處理和 if 語句的話,
請去補基礎知識,這里不多解釋。
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
tearDown 方法在每個測試方法執行后調用,這個地方做所有清理工作,如退出
瀏覽器等。
self.assertEqual([], self.verificationErrors)
這個是難點,對前面 verificationErrors 方法獲得的列表進行比較;如查
verificationErrors 的列表不為空,輸出列表中的報錯信息。
而且,這個東西,也可以將來被你自己更好的調用和使用,根據自己的需要寫入你
希望的信息。(rabbit 告訴我的)
if __name__ == "__main__":
unittest.main()
unitest.main()函數用來測試 類中以 test 開頭的測試用例
這樣一一分析下來,我們對 unittest框架有了初步的了解。運行腳本,因為引入了unittest 框
架,所以控制台輸出了腳本執行情況的信息。
>>> =========================RESTART ================================
>>>
.
----------------------------------------------------------------------
Ran 1 test in 10.656s
OK
>>>
博客園 — 蟲師
http://fnng.cnblogs.com 71
很帥吧!? 后面將以 unittest 為基礎,向新的征程進發~!
二十三、unittest 單元測試框架解析
上一節只是從自動化測試的角度簡單分析了一下 unittest ,這一節從 python 的單元測
試框架的角度再學習一下 unittest 框架(又名 PyUnit 框架)
(好好學,這一章整不明白,后面的技術就別玩了!)
widget.py---被測試類
#coding= utf-8
# 將要被測試的類
class Widget:
def __init__(self, size = (40, 40)):
self._size= size
def getSize(self):
return self._size
def resize(self, width, height):
ifwidth < 0 or height < 0:
raise ValueError, "illegal size"
self._size= (width, height)
def dispose(self):
pass
auto.py---測試類
#coding= utf-8
from widget import Widget
import unittest
# 執行測試的類
class WidgetTestCase(unittest.TestCase):
博客園 — 蟲師
http://fnng.cnblogs.com 72
def setUp(self):
self.widget = Widget()
def testSize(self):
self.assertEqual(self.widget.getSize(), (40, 40))
def tearDown(self):
self.widget = None
# 構造測試集
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase("testSize"))
return suite
# 測試
if__name__ == "__main__":
unittest.main(defaultTest = 'suite')
用 import 語句引入 unittest 模塊
讓所有執行測試的類都繼承於 TestCase 類,可以將 TestCase 看成是對特定類進行
測試的方法的集合
setUp()方法中進行測試前的初始化工作,tearDown()方法中執行測試后的清除工
作。setUp()和 tearDown()都是 TestCase 類中定義的方法
在 testSize()中調用 assertEqual()方法,對 Widget 類中 getSize()方法的返
回值和預期值進行比較,確保兩者是相等的,assertEqual()也是 TestCase 類中
定義的方法。
提供名為 suite()的全局方法,PyUnit 在執行測試的過程調用 suit()方法來確定
有多少個測試用例需要被執行,可以將 TestSuite 看成是包含所有測試用例的一個容
器。
框架分析
軟件測試中最基本的組成是單元測試用例(testcase),我們在實際測試過程中,不
可能真對一個功能(類)只寫一個用例。TestCase 在 PyUnit 測試框架中被視為測試單
元的運行實體,Python 程序員可以通過它派生自定義的測試過程與方法(測試單元),利
博客園 — 蟲師
http://fnng.cnblogs.com 73
用 Command 和 Composite 設計模式,多個 TestCase 還可以組合成測試用例集合。
編寫測試用例
采用 PyUnit 提供的動態方法,只編寫一個測試類來完成對整個軟件模塊的測試,這樣
對象的初始化工作可以在 setUp()方法中完成,而資源的釋放則可以在 tearDown()方法中完
成。
對的 widget.py 被測試類的多方法進行測試
# 執行測試的類
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget()
# 測試 getSize()方法的測試用例
def testSize(self):
self.assertEqual(self.widget.getSize(), (40, 40))
# 測試 resize()方法的測試用例
def testResize(self):
self.widget.resize(100, 100)
self.assertEqual(self.widget.getSize(), (100, 100))
def tearDown(self):
self.widget.dispose()
self.widget = None
我們可以在一個測試類中,寫多個測試用例對被測試類的方法進行測試。
組織用例集
完整的單元測試很少只執行一個測試用例,開發人員通常都需要編寫多個測試用例才能
對某一軟件功能進行比較完整的測試,這些相關的測試用例稱為一個測試用例集,在
PyUnit 中是用 TestSuite 類來表示的。
可以在單元測試代碼中定義一個名為 suite()的全局函數,並將其作為整個單元測試
博客園 — 蟲師
http://fnng.cnblogs.com 74
的入口,PyUnit 通過調用它來完成整個測試過程。
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase("testSize"))
suite.addTest(WidgetTestCase("testResize"))
return suite
如果用於測試的類中所有的測試方法都以 test 開頭,Python程序員甚至可以用
PyUnit 模塊提供的 makeSuite()方法來構造一個。
def suite():
return unittest.makeSuite(WidgetTestCase, "test")
TestSuite 類可以看成是 TestCase 類的一個容器,用來對多個測試用例進行組織,這樣多
個測試用例可以自動在一次測試中全部完成。
運行測試集
PyUnit 使用 TestRunner 類作為測試用例的基本執行環境,來驅動整個單元測試過程。
Python 開發人員在進行單元測試時一般不直接使用 TestRunner 類,而是使用其子類
TextTestRunner 來完成測試,並將測試結果以文本方式顯示出來:
runner= unittest.TextTestRunner()
runner.run(suite)
對 widget.py 被測試類,下面通過 PyUnit 編寫完整的單元測試用例:
text_runner.py
#coding=utf-8
from widget import Widget
import unittest
# 執行測試的類
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget()
def tearDown(self):
self.widget.dispose()
self.widget = None
博客園 — 蟲師
http://fnng.cnblogs.com 75
def testSize(self):
self.assertEqual(self.widget.getSize(), (40, 40))
def testResize(self):
self.widget.resize(100, 100)
self.assertEqual(self.widget.getSize(), (100, 100))
# 測試
if__name__ == "__main__":
# 構造測試集
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase("testSize"))
suite.addTest(WidgetTestCase("testResize"))
# 執行測試
runner= unittest.TextTestRunner()
runner.run(suite)
PyUnit 模塊中定義了一個名為 main 的全局方法,使用它可以很方便地將一個單元測
試模塊變成可以直接運行的測試腳本,main()方法使用 TestLoader 類來搜索所有包含
在該模塊中的測試方法,並自動執行它們。如果 Python 程序員能夠按照約定(以 test
開頭)來命名所有的測試方法,那就只需要在測試模塊的最后加入如下幾行代碼即可:
#coding=utf-8
from widget import Widget
import unittest
# 執行測試的類
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget()
def tearDown(self):
self.widget.dispose()
self.widget = None
def testSize(self):
self.assertEqual(self.widget.getSize(), (40, 40))
def testResize(self):
self.widget.resize(100, 100)
self.assertEqual(self.widget.getSize(), (100, 100))
# 測試
博客園 — 蟲師
http://fnng.cnblogs.com 76
if__name__ == "__main__":
unittest.main()
二十四、批量執行測試集
有了上面對 unittest 框架的學習作鋪墊,下面我們就可以將多個自動化用例用到一起執
行。
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.uiimport Select
from selenium.common.exceptions import NoSuchElementException
import unittest, time, re
class Baidu(unittest.TestCase):
def setUp(self):
self.driver =webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.verificationErrors = []
self.accept_next_alert = True
#百度搜索用例
def test_baidu_search(self):
driver = self.driver
driver.get(self.base_url +"/")
driver.find_element_by_id("kw").send_keys("selenium webdriver")
driver.find_element_by_id("su").click()
time.sleep(2)
driver.close()
#百度設置用例
def test_baidu_set(self):
driver = self.driver
博客園 — 蟲師
http://fnng.cnblogs.com 77
#進入搜索設置頁
driver.get(self.base_url +"/gaoji/preferences.html")
#設置每頁搜索結果為 100 條
m=driver.find_element_by_name("NR")
m.find_element_by_xpath("//option[@value='100']").click()
time.sleep(2)
#保存設置的信息
driver.find_element_by_xpath("//input[@value='保存設置']").click()
time.sleep(2)
driver.switch_to_alert().accept()
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if__name__ == "__main__":
unittest.main()
雖然已經實例了多個用例一起跑,但這樣仍然不合理,幾個用例一起執行還好,如果幾
十個、幾百個的用例的話,這個文件將變得無比龐大,不利於維護。
所以,做合理的做法是一個例一個文件,把所文件放一個文件夾下,通過單獨的腳本控
制所有用例的執行,將腳本的執行結果輸出到一個 log 文件中。
初步把框架走通了。
單個用例相信你早就會寫了,把他們整理一下放到一個文件夾下,然后編寫執行用例集
的腳本:
博客園 — 蟲師
http://fnng.cnblogs.com 78
test_case_.py
#-*-coding=utf-8-*-
import os
#列出某個文件夾下的所有 case,這里用的是 python,所在 py 文件運行一次后會生成一個 pyc
的副本
caselist=os.listdir('D:\\selenium_use_case\\test_case')
for a in caselist:
s=a.split('.')[1:][0] #選取所要執行的用例
ifs=='py':
#此處執行 dos 命令並將結果保存到log.txt
os.system('D:\\selenium_use_case\\test_case\\%s 1>>log.txt 2>&1'%a)
查看 log.txt 文件:
..
----------------------------------------------------------------------
Ran 2 tests in 32.469s
OK
..
----------------------------------------------------------------------
Ran 2 tests in 27.016s
OK
二十五、異常捕捉與錯誤截圖
創建錯誤截圖文件夾,目錄結果如下:
用例不可能每一次運行都成功,肯定運行時候有不成功的時候,換句話說,我們不需要
永遠都運行成功的用例,他本身是沒有什么意義的。關鍵是我們捕捉到錯誤,並以把並錯誤
博客園 — 蟲師
http://fnng.cnblogs.com 79
截圖保存,這將是一個非常棒的功能,也會給我們錯誤定位帶來方便。
baidu.py
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.uiimport Select
from selenium.common.exceptions import NoSuchElementException
import unittest, time, re
class Baidu(unittest.TestCase):
def setUp(self):
self.driver =webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.verificationErrors = []
self.accept_next_alert = True
#百度搜索用例
def test_baidu_search(self):
driver = self.driver
driver.get(self.base_url +"/")
try:
#kwddd 是一個無法找到的元素id
driver.find_element_by_id("kwdddd").send_keys("selenium webdriver")
except:
driver.get_screenshot_as_file("D:\\selenium_use_case\\error_png\\kw.png")
#如果沒有找到上面的元素就截取當前頁面。
driver.find_element_by_id("su").click()
time.sleep(2)
driver.close()
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if__name__ == "__main__":
unittest.main()
這里特意把腳本寫錯誤的,使腳本找不到 id 為 kwddd 的元素,通過 try....except...對
博客園 — 蟲師
http://fnng.cnblogs.com 80
異常進行捕捉;並把結果保存下來。再次執行你的腳本會發現 error_png 目錄下面產生了
錯誤時候的截圖。
截圖函數 get_screenshot_as_file
selenium.webdriver.remote.webdriver.get_screenshot_as_file(filename)
截圖當前窗口圖片。如果有任何 IOError 將返回 false ,否則將返回 Ture .
filename: 指定錯誤截圖的存放路徑及圖片名。
用法:
driver.get_screenshot_as_file(’/Screenshots/foo.png’)
我們需要用 python這門語言去調用 selenium 的一些工具來操作瀏覽器,幫助我們實現
“web UI ”自動化。
===================華麗分割線======================
下面的內容為本文檔第三版的內容,后面的學習重點就不是通過 webdriver如何操作頁
面元素了,我們的關注點將轉移到框架上,如何 python 語言使我們的框架實現更強大的功
能,我在后面的章節學習與整理的過程中,也補充了不少 python 知識,建議讀者最好掌握
一些 python 編程基礎。
博客園 — 蟲師
http://fnng.cnblogs.com 81
二十六、生成測試報告(HTMLTestRunner)
在腳本雲行完成之后,除了在 log.txt 文件看到運行日志外,我們更希望能生一張漂亮
的測試報告來展示用例執行的結果。
下面我們就通過 HTMLTestRunner.py 來生成測試報告。
首先要下 HTMLTestRunner.py 文件,下載 地址:
http://tungwaiyip.info/software/HTMLTestRunner.html
將下載的文件放入...\Python27\Lib 目錄下(windows),打開交互模式引入包,如果沒有
報錯,說明添加成功,當然也可以通過 dir() 看看'HTMLTestRunner 包含發哪些方法。
>>> importHTMLTestRunner
>>> dir(HTMLTestRunner)
['HTMLTestRunner', 'OutputRedirector', 'StringIO', 'Template_mixin', 'TestProgram', 'TestResult',
'_TestResult', '__author__', '__builtins__', '__doc__', '__file__', '__name__', '__package__',
'__version__', 'datetime', 'main', 'saxutils', 'stderr_redirector', 'stdout_redirector', 'sys', 'time',
'unittest']
>>>
ok ! 下面在我們用例中添加可以生成報告的代碼:
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.uiimport Select
from selenium.common.exceptions import NoSuchElementException
import unittest, time, re
import HTMLTestRunner
class Baidu(unittest.TestCase):
博客園 — 蟲師
http://fnng.cnblogs.com 82
def setUp(self):
self.driver =webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com"
self.verificationErrors = []
self.accept_next_alert = True
#測試用例一
def test_baidu_search(self):
#測試用例二
def test_baidu_set(self):
#測試用例三
def test_baidu_xxx(self):
....
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)if __name__ == "__main__":
if__name__ == "__main__":
testunit=unittest.TestSuite() #定義一個單元測試容器
testunit.addTest(Baidu("test_baidu_search")) #將測試用例加入到測試容器中
testunit.addTest(Baidu("test_baidu_set"))
testunit.addTest(Baidu("test_baidu_xxx"))
filename = 'D:\\result.html' #定義個報告存放路徑,支持相對路徑。
博客園 — 蟲師
http://fnng.cnblogs.com 83
fp = file(filename, 'wb')
runner =HTMLTestRunner.HTMLTestRunner(
stream=fp,
title='Report_title',
description='Report_description')
runner.run(testunit) #自動進行測試
代碼分析:
用例的部分通過之前的學習已經非常了解了,下面重點分析底部這段代碼:
testunit=unittest.TestSuite() #定義一個單元測試容器
testunit.addTest(Baidu("test_baidu_search")) #將測試用例加入到測試容器中
testunit.addTest(Baidu("test_baidu_set"))
testunit.addTest(Baidu("test_baidu_xxx"))
filename = 'D:\\result.html' #定義個報告存放路徑,支持相對路徑。
fp = file(filename, 'wb')
runner =HTMLTestRunner.HTMLTestRunner(
stream=fp,
title='Report_title',
description='Report_description')
runner.run(testunit) #自動進行測試
TestSuite 其實並不陌生,在 23 章 章 unittest 單元測試框架分析的部分已經介紹,只是為
了方便我們使用了 unittest.main() 方法,默認會將所有用例執行。因為這里要生成報告,所
以要將所有用例列出;
博客園 — 蟲師
http://fnng.cnblogs.com 84
下面的也很容易理解,創建 result.html 文件,給以讀寫權限(wb),調用HTMLTestRunner
文件,並將測試結果以HTMLTestRunner 規定的格式通過fp 傳遞寫入到result.html 文件中。
最后是運行的 testunit ,也就是 TestSuite 中的所有用例。
腳本運行結束,生成如下報告:
問題:
這個報告是根據一個.py 文件生成的,這樣就迫使我們把所有用例都寫在一個.py 文件
里,如果我們每一個用例都寫在不同的.py 文件里將生成很多個報告,不便於閱讀;但寫在
一個.py 文件里,如果用例非常多的話,同樣不便於維護。
后面,我們將一起尋求解決辦法。
二十七、數據驅動測試
先來理解一下自動化領域的兩種驅動,對象驅動與數據驅動。
數據驅動:測試數據的改變引起執行結果的改變 叫 數據驅動;
關鍵字驅動:測試對象名字的改變起引起測試結果的改變 叫 關鍵字驅動。
27.1 、讀取文件參數化
博客園 — 蟲師
http://fnng.cnblogs.com 85
以百度表搜索為例,我們可以通過腳本循環執行,讀取一文件中不同的內容來完成自動
化工作,也就是說我們每次取的文件里的搜索關鍵字不同,而每次百度搜索的的結果不同,
這也是數據驅動的本質。
代碼如下:
d:\abc\data.txt
baidu_read_data.py
#coding=utf-8
from selenium import webdriver
import os,time
source= open("D:\\abc\\data.txt", "r")
values = source.readlines()
source.close()
# 執行循環
for serch in values:
browser =webdriver.Firefox()
browser.get("http://www.baidu.com")
browser.find_element_by_id("kw").send_keys(serch)
browser.find_element_by_id("su").click()
browser.quit()
這里簡單說明一下,open方法左以只讀方式(r)打開本地的 data.txt 文件,readlines
方法是逐行的讀取文件內容。
通過 for 循環,serch 可以每次獲取到文件中的一行數據,在定位到百度的輸入框后,
博客園 — 蟲師
http://fnng.cnblogs.com 86
將數據傳入 send_keys(serch)。這樣通過循環調用,直到文件的中的所有內容全被讀取。
27.2 、用戶名密碼的參數化(讀取文件)
按照上面的方法,對自動化腳本中用戶名密碼進行參數化應該很簡單,其實沒有想象的
那么簡單,從目前我所查到 python 讀取方法有,整個文件讀取,逐行讀取,固定字節讀取。
怎樣才一次讀取用戶名和密碼兩個信息呢,最初的修改是這樣的:
創建兩個文件,分別存放用戶名密碼
調用用戶名密碼登錄登錄的腳本
#coding=utf-8
from selenium import webdriver
import os,time
source= open("D:\\abc\\data2.txt", "r") #用戶名文件
user = source.read(5) #用戶名長度
source.close()
source2 = open("D:\\abc\\data3.txt", "r") #密碼文件
pw =source2.read(6) #密碼長度
source2.close()
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fwebcloud.kuaibo.com%2
F")
driver.find_element_by_id("user_name").clear()
driver.find_element_by_id("user_name").send_keys(user)
time.sleep(3)
driver.find_element_by_id("user_pwd").clear()
driver.find_element_by_id("user_pwd").send_keys(pwd)
time.sleep(3)
博客園 — 蟲師
http://fnng.cnblogs.com 87
driver.find_element_by_name("Submit").click()
time.sleep(1)
driver.quit()
缺點:
雖然目的達到了這,但這樣的實現有很多問題:
1、用戶名密碼分別在不同的文件里,這樣就要求用戶名密碼必須一一對應
2、必須指定讀取的長度,測試 readlines() 並不是讀取的一行數據。
3、無法循環讀取。
27.3 、用戶名的參數化(字典)
用戶名密碼參數化
解決循環調用
通過一整天研究,重新補習 python 字典、函數調用,如果固定只是讀取用戶名,密碼
兩個值,可以通過如下方法實現。
創建 fun.py 文件,定義一個字典方法:
def zidian():
d={'fnngj':'a23456','testing360':123456}
print "suess read usernameand password!!"
return d
字典的可以方便的存放 k,v鍵值對,一個鍵對應一個值;注意,如果密碼中有非數字,
需要加單引號。
下面循環調用詞典的值:
#coding=utf-8
from selenium import webdriver
import os,time
import fun #導入函數
博客園 — 蟲師
http://fnng.cnblogs.com 88
#循環調用字典里的用戶名密碼,分別賦值給 k,v
for k,v in fun.zidian().items():
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fwebcloud.kuaibo
.com%2F")
driver.find_element_by_id("user_name").clear()
driver.find_element_by_id("user_name").send_keys(k)
time.sleep(3)
driver.find_element_by_id("user_pwd").clear()
driver.find_element_by_id("user_pwd").send_keys(v)
time.sleep(3)
driver.find_element_by_id("dl_an_submit").click()
time.sleep(1)
driver.close()
腳本這樣表設計就穩定了很多,每次取的值非常固定,而且同樣實現了參數與腳本分離,
如果幾百個腳本都調用 fun( ) 函數,當需要修改用戶名密碼時,只用修改 fun( )函數里面字
典的值就可以了。
27.4 、用戶名密碼的參數化(函數)
其實,在我的項目中只需要做到參數化就行了,並不需要循環的讀取內容。那么通過函
數調用就可以很簡單的解決。
fun.py
def user(k='fnngj',v=123456):
print "suess read username and password!!"
return k,v
賦默認值,並將結果返回。
調用函數值:
#coding=utf-8
博客園 — 蟲師
http://fnng.cnblogs.com 89
from selenium import webdriver
import os,time
import fun #導入函數
#通過調用函數獲得用戶名&密碼
k,v = fun.user()
print k,v
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fwebcloud.kuaibo
.com%2F")
driver.find_element_by_id("user_name").clear()
driver.find_element_by_id("user_name").send_keys(k)
driver.find_element_by_id("user_pwd").clear()
driver.find_element_by_id("user_pwd").send_keys(v)
driver.find_element_by_id("dl_an_submit").click()
time.sleep(3)
driver.close()
運行結果:
>>> =================== RESTART ================================
>>>
suess read username and password!!
fnngj 123456
.
----------------------------------------------------------------------
Ran 1 test in 25.484s
OK
博客園 — 蟲師
http://fnng.cnblogs.com 90
如果學好了 python 語言,解決問題的方法是多樣的,使用最貼合需求的方法,簡單解
決問題。這一節寫的比較多,對構建自動化框架來說,參數化是非常重要的一個知識點。
二十八、測試套件
在 23 章單元測試框架解析中我提了到“測試套件”,當時只是把一個.py 文件里的多個
用例通過測試套件執行。批量執行測試集中 雖然可以批量執行多個.py 文件,但它使用的
是讀取文件夾下文件的方式,而不是使用的測試套件。這一節就使用測試套件來執行多個.py
測試文件。
最終我們全通過測試套件完成下面的結構:
測試套件的問題解決了,26 章生成測試報告遺留的問題自然也可以解決了。
28.1 、測試套件實例
下面通過一個例子來組建我們的測試套件。
test_youdao.py
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
博客園 — 蟲師
http://fnng.cnblogs.com 91
from selenium.webdriver.support.uiimport Select
from selenium.common.exceptions import NoSuchElementException
import unittest, time, re
import HTMLTestRunner
class Youdao(unittest.TestCase):
def setUp(self):
self.driver =webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com"
self.verificationErrors = []
self.accept_next_alert = True
#百度搜索用例
def test_youdao_search(self):
driver = self.driver
driver.get(self.base_url +"/")
try:
driver.find_element_by_id("query").send_keys(u"蟲師")
driver.find_element_by_id("qb").click()
time.sleep(2)
except:
driver.get_screenshot_as_file("D:\\selenium_use_case\\error_png\\kw.png")
#如果沒有找到上面的元素就截取當前頁面。
def tearDown(self):
self.driver.quit()
博客園 — 蟲師
http://fnng.cnblogs.com 92
self.assertEqual([], self.verificationErrors)
if__name__ == "__main__":
suite = unittest.TestSuite()
suite.addTest(Youdao("test_youdao_search"))
#這里可以添加更多的用例,如:
#suite.addTest(Youdao("aaaa"))
unittest.TextTestRunner().run(suite)
test_baidu.py
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.uiimport Select
from selenium.common.exceptions import NoSuchElementException
import unittest, time, re
import HTMLTestRunner
class Baidu(unittest.TestCase):
def setUp(self):
self.driver =webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com"
self.verificationErrors = []
self.accept_next_alert = True
博客園 — 蟲師
http://fnng.cnblogs.com 93
#百度搜索用例
def test_baidu_search(self):
driver = self.driver
driver.get(self.base_url +"/")
try:
#是一個無法找到的元素 id
driver.find_element_by_id("kw").send_keys("selenium webdriver")
except:
driver.get_screenshot_as_file("D:\\selenium_use_case\\error_png\\kw.png")
#如果沒有找到上面的元素就截取當前頁面。
driver.find_element_by_id("su").click()
time.sleep(2)
driver.close()
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if__name__ == "__main__":
suite = unittest.TestSuite()
suite.addTest(Baidu("test_baidu_search"))
#同樣的,可以在這個文件中添加更多的用例。
#suite.addTest(Youdao("aaaa"))
results= unittest.TextTestRunner().run(suite)
通過測試套件運行上面兩個測試文件,創建 all_tests.py 文件
博客園 — 蟲師
http://fnng.cnblogs.com 94
#coding=utf-8
"Combine tests for gnosis.xml.objectify package(req 2.3+)"
import unittest, doctest
import test_baidu, test_youdao #這里需要導入測試文件
import HTMLTestRunner
suite = doctest.DocTestSuite()
#羅列要執行的文件
suite.addTest(unittest.makeSuite(test_baidu.Baidu))
suite.addTest(unittest.makeSuite(test_youdao.Youdao))
unittest.TextTestRunner(verbosity=2).run(suite)
運行結果:
>>> =========================RESTART ================================
>>>
test_baidu_search (test_baidu.Baidu) ... ok
test_youdao_search (test_youdao.Youdao) ... ok
----------------------------------------------------------------------
Ran 2 tests in 15.140s
OK
28.2 、整合 HTMLTestRunner 測試報告
生成 HTMLTestRunner 報告和前面的方法一樣,只是把代碼移動 all_tests.py 文件即可;
而且只需要在這一個地方生成即可。
下面看加入 HTMTestRunner之后的 all_tests.py 文件
博客園 — 蟲師
http://fnng.cnblogs.com 95
#coding=utf-8
"Combine tests for gnosis.xml.objectify package(req 2.3+)"
import unittest, doctest
#這里需要導入測試文件(test_baidu.py,test_youdao.py)
import test_baidu,test_youdao
import HTMLTestRunner
suite = doctest.DocTestSuite()
suite.addTest(unittest.makeSuite(test_baidu.Baidu))
suite.addTest(unittest.makeSuite(test_youdao.Youdao))
filename = 'D:\\result20.html'
fp = file(filename, 'wb')
runner=HTMLTestRunner.HTMLTestRunner(
stream=fp,
title='Report_title',
description='Report_description')
runner.run(suite)
代碼都是前面見過的,這里就不費口舌了再解析了;如果不太理解就多敲幾遍,自然就
理解。運行測試報告如下,這樣再多文件的用例都可以放到一張報告里了。
博客園 — 蟲師
http://fnng.cnblogs.com 96
28.3 、更易讀的報告
報告已經接近完美了,唯一的一點小瑕疵,這報告如果給領導看的話,哪知道什么是什
么,經過 MarkRabbit 的指點,我們可以給每一個用例加個中文注釋。
............
#百度搜索用例
def test_baidu_search(self):
u"""百度搜索用例"""
driver = self.driver
driver.get(self.base_url +"/")
................
每個用例(方法)下面都可以加這個一行注釋信息,小 u 是避免中文引起的亂碼問題。
博客園 — 蟲師
http://fnng.cnblogs.com 97
再來跑一下用例,找開生成的報告,是不是完美了,傻瓜都知道是干嘛的。
二十九、結構改進
到目前為止問題已經解決了,通過測試套件執行所有用例,測試報告整合,所有文件都
在一個目錄下面,估計用例寫多了,不方便管理,這一章試着調整一下結構。
29.1 、all_tests.py 移出來
all_tests.py 是調用例的程序,而不是執行用例的,所以應該把它移出來。結構上會
更為合理。
/selenium_use_case/test_case/untie/test_baidu.py
/unite/test_baidu.py
/unite/__init__.py
/unite/...
/all_tests.py
目錄結構應該是這樣的,untie 文件夾下存放具體的執行用例,all_tests.py 應該與 untie
文件夾平級。
另外,需要在 unite 文件夾下放一個__init__.py 文件,文件內容可以為空。
那么直接移出來后再運行 all_tests.py 文件會提示不到測試文件,所以,我們要對代碼
做調整,把文件夾加到 sys.path 下就可以找到了。在 all_tests.py 頭部添加以下內容。
.......
博客園 — 蟲師
http://fnng.cnblogs.com 98
import sys
sys.path.append("/selenium_use_case/test_case")
from sutie import test_youdao
from sutie import test_baidu
.....
29.2 、__init__.py 文件解析
all_tests.py 是移出來了,但是還有個問題,導入包(用例文件)也是個問題,假如幾個
用例可以通過“from sutie import test_xxx” 的方式導入,假如成幾百條呢,這樣羅列幾百
條,做法確實太二;那有沒有不那么二的方式呢。
還記得上面提到的__init__.py 文件吧,這文件是干嘛的,為什么要在引用的目錄下加這
個文件?
要弄明白這個問題,首先要知道,python 在執行 import 語句時,到底進行了什么操作,按照
python 的文檔,它執行了如下操作:
第 1 步,創建一個新的,空的 module 對象(它可能包含多個 module);
第 2 步,把這個 module 對象插入 sys.module 中
第 3 步,裝載 module 的代碼(如果需要,首先必須編譯)
第 4 步,執行新的 module 中對應的代碼。
在執行第 3 步時,首先要找到 module 程序所在的位置,搜索的順序是:
當前路徑 (以及從當前目錄指定的 sys.path),然后是 PYTHONPATH,然后是 python 的安
裝設置相關的默認路徑。正因為存在這樣的順序,如果當前 路徑或 PYTHONPATH 中存在與標准
module 同樣的 module,則會覆蓋標准 module。也就是說,如果當前目錄下存在 xml.py,那么
執 行 import xml 時,導入的是當前目錄下的 module,而不是系統標准的 xml。
了解了這些,我們就可以先構建一個 package,以普通 module 的方式導入,就可以直接訪問
此 package 中的各個 module 了。python 中的 package 必須包含一個__init__.py 的文件。
------以上引用“老王 python”
博客園 — 蟲師
http://fnng.cnblogs.com 99
其實__init__.py 文件中可以有內容; 我們在導入一個包時,實際上導入了它的
__init__.py 文件。
在__init__.py 文件中添加導入包
import test_baidu
import test_youdao
然后,all_tests.py 文件可是這樣修改:
.......
import sys
sys.path.append("/selenium_use_case/test_case")
from sutie import *
.....
“*” 星號表示導入 sutie 目錄下的所有文件;在 sutie 目錄下創建測試用例文件,只用
在__init__.py 文件下羅列就可以了。而對於 all_tests.py 文件來說不需要做任何調整。
29.3 、調用多級目錄的用例
當測試用例達到一定量級的時候,為了便於管理,必定需要在目錄下面再分目錄。假設
我們有這樣一個結構:
/selenium_use_case/test_case/untie/test_baidu.py
/unite/test_baidu.py
/unite/sogou/test_sogou.py ----二級測試用例目錄
/unite/sogou/__init__.py
/unite/sogou/...
/unite/__init__.py
/unite/...
/all_tests.py
其實,這個問題也很好處理,接着分析__init__.py 文件,它處了能導入當前目錄下的
博客園 — 蟲師
http://fnng.cnblogs.com 100
文件,是不是還可以導入其它目錄下包,或者模塊。假設在/unite/sogou/目錄下創建了
test_sogou.py 測試文件,修改 unite 目錄__init__.py 文件:
#coding=utf-8
import sys
sys.path.append("/selenium_use_case/test_case/sutie")
from sogou import *
import test_baidu
import test_youdao
別忘了/unite/sogou/ 目錄下也要加__init__.py 文件,並且加入包。掌握的這個技巧,再
也不用擔心多級目錄的問題了。
29.4 、改進用例的讀取
你以為這樣就算完了么? 還有個更嚴峻的問題需要處理,如果你夠警覺一定注意
all_tests.py 的這段代碼:
....
suite = doctest.DocTestSuite()
suite.addTest(unittest.makeSuite(test_baidu.Baidu))
suite.addTest(unittest.makeSuite(test_youdao.Youdao))
suite.addTest(unittest.makeSuite(test_sogou.Sogou))
.....
對的,這也是無法回避的一個硬傷,跟導入包一樣無法避免,想想成百的用例羅列到這
里是多么痛的領悟。。
最先想到的是能不能通過一個循環來解決掉這個問題,循環的讀取某個目錄下的所有文
件;如果你還記得本文檔的 第 24章 章 有一個叫 test_case_.py 的文件的話,讀取某個文件夾
下的所有文件是一件很簡單的事情;但是如何將結果生成到報告里呢。解決這個問題還是稍
微有那么一點兒難度的。
經過改進的新 all_tests.py 代碼如下:
博客園 — 蟲師
http://fnng.cnblogs.com 101
#coding=utf-8
import sys ,re ,os,math
sys.path.append("/selenium_use_case/test_case")
from sutie import *
import unittest, doctest ,site
import HTMLTestRunner
#將用例組建成數組
alltestnames = [
'sutie.test_baidu.Baidu',
'sutie.test_youdao.Youdao',
'sutie.sogou.test_sogou.Sogou', #注意這個用例是二級目錄下的
]
suite =unittest.TestSuite()
if __name__== '__main__':
# 這里我們可以使用 defaultTestLoader.loadTestsFromNames(),
# 但如果不提供一個良好的錯誤消息時,它無法加載測試
# 所以我們加載所有單獨的測試,這樣將會提高腳本錯誤的確定。
fortest inalltestnames:
try:
#最關鍵的就是這一句,循環執行數據數的里的用例。
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(test))
except Exception:
print 'ERROR: Skipping tests from "%s".' % test
try:
__import__(test)
except ImportError:
print 'Could not importthetest module.'
else:
print 'Could not load the test suite.'
from traceback import print_exc
print_exc()
print
print 'Running the tests...'
filename = 'D:\\result21.html'
博客園 — 蟲師
http://fnng.cnblogs.com 102
fp = file(filename,'wb')
runner =HTMLTestRunner.HTMLTestRunner(
stream=fp,
title='Report_title',
description='Report_description')
runner.run(suite)
代碼解析,為了做到只解決當前面的問題,上面的代碼做了很多簡化。其實,我們可以
在這里完成更多的功能。
首先我們以“目錄.用例文件.用例類”的格式將用例放到一個數組中,可以這樣做的前
提是我們導入了測試用例文件;然后組成了 alltestnames 數組。
通過一個 for 循環來讀取數組的內容;讀取的方法是:
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(test))
緊接的 try...except... 是對異常的處理,如果不理解,可以暫無視或刪除異常捕捉
的相關代碼,使代碼更清爽。
下面的代碼已經見過好多次了,是用於生成 HTMLTestRunner 報告的。
29.5 、進一步分離用例列表
都到進一步分,下面知道該怎么做了吧!? 翻一下 第 27.3節 節 參數化中的字典,應該能
找到方法。都把用例組成數組了,我們要做的就是把它放到一個單獨的文件里。
創建 allcase_list.py 文件,與 all_tests.py 在同一級目錄下。把數組放到一個方法
里,allcase_list.py 內容如下:
def caselist():
alltestnames = [
'sutie.test_baidu.Baidu',
'sutie.test_youdao.Youdao',
'sutie.sogou.test_sogou.Sogou',
]
print "suess read case list success!!"
博客園 — 蟲師
http://fnng.cnblogs.com 103
return alltestnames
在 all_tests.py 中進行調用:
#coding=utf-8
....
import allcase_list #調用數組文件
#獲取數組方法
alltestnames = allcase_list.caselist()
...
suite =unittest.TestSuite()
if __name__== '__main__':
fortest inalltestnames:
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(test))
.....
現在現在優雅多了,把需要的執行的用例往 allcase_list.py 的數組是羅列就行了。
用例的調整,all_tests.py 文件不需要做任何的修改。
最后再回顧一下我們有目前測試的目錄結構:
/selenium_use_case/test_case/untie/test_baidu.py -----一級目錄測試用例
/unite/test_baidu.py
/unite/sogou/test_sogou.py ----二級目錄測試用例目錄
/unite/sogou/__init__.py
/unite/sogou/...
/unite/__init__.py
/unite/...
/all_tests.py ----調用所有腳本執行
/allcase_list.py -----羅列要執行的用例
/test_result/result1.html ----測試報告的存入目錄
博客園 — 蟲師
http://fnng.cnblogs.com 104
目前看上去還不錯的樣子~!(得意笑),但是我們項目不同,需求不同,或者當用例達
到一定量級后,還會有很多問題暴露出來,需要我們一一的去解決;好吧~!第三版的內容
就到這里了。
三十、UliPad--python 開發利器
工欲善其事,必先利其器
有時候往往選擇太多,變得無從選擇。如果你在 python 開發中已經找到了趁手的 IDE這
一節可以無視。
其實,pyhon下面能找到一款不錯的開發工具是不太容易的。
IDLE 寫寫單個小程序很好,但一個程序文件與執行信息是兩個窗口,程序開多了就分
不清哪個了。
pythonWin 也用過,窗口有些老土,窗口布局我不會設置,所以覺得也不好用。
notepad++ 這種小巧的萬能編輯器,偶爾用用還行。
x linux 會有一些非常不錯的交互式python IDE ,如 ipython、bpython 等。
m vim 肯定是開發神器,但一般也只有高手才會運用自如,體會它的奧妙。
UliPad 是找到的寫 python 最舒服的一個 IDE 。
地址: https://code.google.com/p/ulipad/
免費,可以免費獲得並使用它的所有功能。
支持 windows 、MAC、linux 等平台。
小巧,內存占用很少,10MB 左右。
博客園 — 蟲師
http://fnng.cnblogs.com 105
具體,的安裝使用,這里就不介紹了,不是本文檔的主題。有興趣使用可以參考我的博客:
http://www.cnblogs.com/fnng/p/3393275.html
另外,還有一些非常棒的收費 python IDE
Wing IDE4.1
http://wingware.com/
pycharm
http://www.jetbrains.com/pycharm/
希望這一節沒影響到文檔的和諧。呵呵~!
博客園 — 蟲師
http://fnng.cnblogs.com 106
后記:
都在談自動化測試,自動化測試是“部分”功能測試的一種替代技術(它們比例肯定在
逆轉)。通過學習自動腳本也可以使測試人員突破不懂代碼的限制;而自動化腳本入門簡單。
我覺得自動化是方向。
關於自動化又幫了你一段路,但是,依然還有很多問題沒有解決;比如,測試用例的多
線程處理。目前的結構還不夠完美,在腳本運行中,我們可以捕捉更多的信息,更容易的定
位問題;使我們的結構更靈活的適應需求的變化;路還很長,任重道遠,一起加油吧!
這些問題依然不是一份學習文檔可以解決的,如果你掌握了本文檔的所有內容,建議從
以下幾個方面來提高自己的自動化測試水平:
python 語言:兔子(它不讓叫兔子了,叫 t MarkRabbit )的話清晰的說明了學習自動
化測試的思路:我們需要用 python 這門語言去調用 selenium 的一些工具來操作瀏覽器,
幫助我們實現“web UI ”自動化。所以,我們的重心應該放在語言本身的學習。后面這幾
章解決問題用的也是 python 技術。
Javascript 語言:在實際的自動化測試過程中,我們會遇到各種問題,有時候 webdriver
提供的方法不能幫我們解決問題,那么需要借助 Javascript 來解決問題。
xpath \css 定位: 不能操作一個元素,很多情況下是我們沒辦法定位這個元素;所以要
深入了解 xpath \css 定位的用法。
擴展資料:
rtsm eyiselenium 與webdriver 的關系:
http://v.qq.com/boke/page/j/v/v/j01135krrvv.html
lazyman 快速入門:
http://v.qq.com/boke/page/i/k/a/i0113wompka.html
關於 python 自動化的博客,慢慢研讀:
博客園 — 蟲師
http://fnng.cnblogs.com 107
http://www.cnblogs.com/hzhida/archive/2012/08/13/2637089.html
splinter 自動化框架:
http://splinter.cobrateam.info/docs/why.html
http://v.qq.com/boke/page/s/8/3/s0114uu1d83.html。
大家可以了解一下webdriverguide的內容
webdriverAPI地址:
https://github.com/easonhan007/webdriver_guide
robot framework
自動化測試框架,后序研究。
RF框架系列文章
http://www.51testing.com/?21116/
http://blog.csdn.net/tulituqi/article/category/897484/2
安裝:http://blog.sina.com.cn/s/blog_654c6ec70100tkxn.html
selenium webdriver py 文檔
http://selenium.googlecode.com/git/docs/api/py/index.html
r seleniumwrapper 0.5.3
https://pypi.python.org/pypi/seleniumwrapper
selenium webdriver 系列教程
http://blog.csdn.net/nbkhic/article/details/6896889
文檔
http://selenium.googlecode.com/git/docs/api/py/index.html
phantomJS
