WebDriver的工作原理及常用方法大全
WebDriver的工作原理
在我們new一個WebDriver的過程中,Selenium首先會確認瀏覽器的native component是否存在可用而且版本匹配。接著就在目標瀏覽器里啟動一整套Web Service(實際上就是瀏覽器廠商提供的driver, 比如IEDriver, ChromeDriver,它們都實現(xiàn)了WebDriver's wire protocol.),這套Web Service使用了Selenium自己設計定義的協(xié)議,名字叫做The WebDriver Wire Protocol。
WebDriver Wire協(xié)議是通用的,也就是說不管是FirefoxDriver還是ChromeDriver,啟動之后都會在某一個端口啟動基于這套協(xié)議的Web Service。例如FirefoxDriver初始化成功之后,默認會從http://localhost:7055開始,而ChromeDriver 則大概是http://localhost:46350之類的。
接下來,我們調(diào)用WebDriver的任何API,都需要借助一個 ComandExecutor發(fā)送一個命令,實際上是一個HTTP request給監(jiān)聽端口上的Web Service。在我們的HTTP request的body中,會以WebDriver Wire協(xié)議規(guī)定的JSON格式的字符串來告訴Selenium我們希望瀏覽器接下來做什么事情。
WebDriver 啟動目標瀏覽器,并綁定到指定端口。該啟動的瀏覽器實例,做為web driver的remote server
Client 端通過CommandExcuter 發(fā)送HTTPRequest 給remote server 的偵聽端口(通信協(xié)議:the webriver wire protocol)
Remote server 需要依賴原生的瀏覽器組件(如:IEDriver.dll,chromedriver.exe),來轉(zhuǎn)化轉(zhuǎn)化瀏覽器的native調(diào)用。
那么remoteserver端的這些功能是如何實現(xiàn)的呢?答案是瀏覽器實現(xiàn)了webdriver的統(tǒng)一接口,這樣client就可以通過統(tǒng)一的restful的接口去進行瀏覽器的自動化操作。目前webdriver支持ie, chrome, firefox, opera等主流瀏覽器,其主要原因是這些瀏覽器實現(xiàn)了webdriver約定的各種接口。
可以更通俗的理解:由于客戶端腳本(java,python,ruby)不能直接與瀏覽器通信,這時候可以把WebService當做一個翻譯器,它可以把客戶端代碼翻譯成瀏覽器可以識別的代碼(比如js).客戶端 (也就是測試腳本)創(chuàng)建1個session,在該session中通過http請求向WebService發(fā)送restful的請求,WebService翻譯成瀏覽器懂得腳本傳給瀏覽器,瀏覽器把執(zhí)行的結(jié)果返回給WebService,WebService把返回的結(jié)果做了一些封 裝(一般都是json格式),然后返回給client,根據(jù)返回值就能判斷對瀏覽器的操作是不是執(zhí)行成功
摘自官網(wǎng)對于chrome driver的描述:
The ChromeDriver consists of three separate pieces. There is the browser itself ("chrome"), the language bindings provided by the Selenium project ("the driver") and an executable downloaded from the Chromium project which acts as a bridge between "chrome" and the "driver". This executable is called "chromedriver", but we'll try and refer to it as the "server" in this page to reduce confusion.
大概意思就是我們下載的chrome可執(zhí)行文件(.exe)是為作為瀏覽器與client(language binding)橋梁的作用,也更印證了對于Web Service(driver)的理解。
舉個實際的例子:
WebDriver diver = new FirefoxDriver();
driver.get("http://google.com");
在執(zhí)行 driver.get("http://google.com"); 這句代碼時,client也就是我們的測試代碼向Web Service(remote server)發(fā)送了如下的請求:
POST session/285b12e4-2b8a-4fe6-90e1-c35cba245956/url
post_data {"url":"http://google.com"}
通過post的方式請求localhost:port/hub/session/session_id/url地址,請求瀏覽器完成跳轉(zhuǎn)url的操作。
如果上述請求是可接受的,或者說Web Service是實現(xiàn)了這個接口,那么Web Service會跳轉(zhuǎn)到該post data包含的url,并返回如下的
response
{"name":"get","sessionId":"285b12e4-2b8a-4fe6-90e1-c35cba245956","status":0,"value":""}
該response中包含如下信息 name:Web Service端的實現(xiàn)的方法的名稱,這里是get,表示跳轉(zhuǎn)到指定url;sessionId:當前session的id;status:請求執(zhí)行的狀態(tài)碼,非0表示未正確執(zhí)行,這里是0,表示一切ok不必擔心;value:請求的返回值,這里返回值為空,如果client調(diào)用title接口,則該值應該是當前頁面的title;
如果client發(fā)送的請求是定位某個特定的頁面元素,則response的返回值可能是這樣的:
{"name":"findElement","sessionId":"285b12e4-2b8a-4fe6-90e1-c35cba245956","status":0,"value":{"ELEMENT":"{2192893e-f260-44c4-bdf6-7aad3c919739}"}}
name,sessionId,status跟上面的例子是差不多的,區(qū)別是該請求的返回值是ELEMENT:{2192893e- f260-44c4-bdf6-7aad3c919739},表示定位到元素的id,通過該id,client可以發(fā)送如click之類的請求與 server端進行交互。
WebDriver的常用方法
日常操作
from selenium import webdriver
from time import sleep
# 創(chuàng)建谷歌瀏覽器對象
chrome_driver = webdriver.Chrome()
# 訪問百度
chrome_driver.get("http://www.baidu.com")
# 最大化窗口
chrome_driver.maximize_window()
# 訪問檸檬班
chrome_driver.get("https://lemon.ke.qq.com/")
# 后退
chrome_driver.back()
# 前進,要有歷史記錄
chrome_driver.forward()
# 刷新
chrome_driver.refresh()
# 等待10s,更明顯看出效果
sleep(10)
# 關(guān)閉窗口,關(guān)閉當前窗口
chrome_driver.close()
# 等待10s,更明顯看出效果
sleep(10)
# 關(guān)閉會話,關(guān)閉瀏覽器,關(guān)閉driver
chrome_driver.quit()
鼠標事件
from selenium import webdriver
# 引入 ActionChains 類
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome() driver.get("https://www.baidu.cn")
# 定位到要懸停的元素
above = driver.find_element_by_link_text("設置") # 對定位到的元素執(zhí)行鼠標懸停操作
ActionChains(driver).move_to_element(above).perform()
'''
perform(): 執(zhí)行操作
context_click(): 右擊;
double_click(): 雙擊;
drag_and_drop(): 拖動;
move_to_element(): 鼠標懸停
'''
鍵盤事件
from selenium import webdriver
# 引入 Keys 模塊
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome ()
driver.get("http://www.baidu.com")
#輸入框輸入內(nèi)容
driver.find_element_by_id ("kw").send_keys("seleniumm")
#刪除多輸入的一個m
driver.find_element_by_id ("kw").send_keys(Keys.BACK_SPACE)
'''
刪除鍵(BackSpace)send_keys(Keys.BACK_SPACE)
空格鍵 (Space)send_keys(Keys.SPACE)
制表鍵(Tab) send_keys(Keys.TAB)
回退鍵(Esc)send_keys(Keys.ESCAPE)
回車鍵(Enter)send_keys(Keys.ENTER)
全選(Ctrl+A)send_keys(Keys.CONTROL,‘a(chǎn)’)
復制(Ctrl+C)send_keys(Keys.CONTROL,‘c’)
剪切(Ctrl+X)send_keys(Keys.CONTROL,‘x’)
粘貼(Ctrl+V)send_keys(Keys.CONTROL,‘v’)
鍵盤 F1 send_keys(Keys.F1)
鍵盤 F12send_keys(Keys.F12)
'''
上傳文件
driver.find_element_by_id("albumUpload").send_keys("文件路徑")
#通過模擬鍵盤敲擊上傳
from selenium.webdriver.common.action_chains import ActionChains
from selenium import webdriver
import win32com.client # python -m pip install pypiwin32
ActionChains(driver).click(driver.find_element_by_id("albumUpload")).perform()
sh = win32com.client.Dispatch("WScript.shell")
time.sleep(3)
# 1、代碼不聯(lián)想 2、輸入法要保持英文輸入狀態(tài) 3、無法處理中文
sh.Sendkeys("文件路徑\r\n")
'''
上傳多個文件
通過輸入文件路徑上傳
"文件1路徑\n文件2路徑"
通過模擬鍵盤上傳
'"文件1路徑" "文件2路徑\r\n"'
'''
內(nèi)嵌網(wǎng)頁iframe切換
# 定位到內(nèi)嵌網(wǎng)頁
ele = driver.find_element_by_css_selector("[class=\"ke-edit-iframe\"]")
# 切入內(nèi)嵌網(wǎng)頁中
driver.switch_to.frame(ele)
driver.find_element_by_css_selector("[class=\"ke-content\"]").send_keys("123")
# 切入內(nèi)嵌網(wǎng)頁后,若想再操作內(nèi)嵌網(wǎng)頁外的元素,需要再切出來
driver.switch_to.default_content()
瀏覽器標簽頁切換
win_sli = driver.window_handles # 獲取當前所有標簽頁的句柄
# 循環(huán)所有標簽,直到找到標題、url、頁面元素相符的標簽,就停止切換,停留在當前標簽頁
for win in win_sli:
driver.switch_to.window(win)
# 如果標簽頁的標題不固定,還可以用網(wǎng)址判斷
# 如果網(wǎng)址和標題都不固定,可以找一個目標標簽頁獨有的元素,然后判斷元素是否存在
if driver.title == "OPMS-項目管理軟件+OA管理軟件+CRM管理軟件":
break
'''
current_window_handle:獲得當前標簽頁句柄
window_handles:返回所有便簽頁的句柄
switch_to.window(標簽頁句柄):切換到對應的標簽頁
關(guān)閉標簽頁使用 close 方法
'''
頁面滾動
driver.execute_script(“window.scrollBy(0,500)”)
driver.execute_script(“arguments[0].scrollIntoView();”, ele)
'''
window.scrollBy(0,500) 向下滾動500個像素
window.scrollBy(0,-500) 向上滾動500個像素
window.scrollBy(500,0) 向右滾動500個像素
window.scrollBy(-500,0) 向左滾動500個像素
'''
截圖
# 截圖,截取全屏,參數(shù)為要保存圖片的文件路徑,官方建議用png格式
# 如果想截取登陸以后的界面:1、sleep 2、尋找一個登錄后才有的元素
driver.get_screenshot_as_file("./a.png")
# 對元素進行截圖
ele = driver.find_element_by_css_selector("[class=\"nav nav-pills nav-stacked custom-nav js-left-nav\"]")
ele.screenshot("./b.png")
警告框處理
# 獲取對話框?qū)ο?br>al = driver.switch_to.alert
# 確認對話框
al.accept()
'''
text:返回 alert/confirm/prompt 中的文字信息
accept():接受現(xiàn)有警告框
dismiss():取消現(xiàn)有警告框
send_keys(“haha”):發(fā)送文本至警告框
'''
作者: Python測試社區(qū)
歡迎關(guān)注微信公眾號 :Python測試社區(qū)