WebDriver的工作原理及常用方法大全

WebDriver的工作原理

在我們new一個WebDriver的過程中,Selenium首先會確認(rèn)瀏覽器的native component是否存在可用而且版本匹配。接著就在目標(biāo)瀏覽器里啟動一整套Web Service(實(shí)際上就是瀏覽器廠商提供的driver, 比如IEDriver, ChromeDriver,它們都實(shí)現(xiàn)了WebDriver's wire protocol.),這套Web Service使用了Selenium自己設(shè)計(jì)定義的協(xié)議,名字叫做The WebDriver Wire Protocol。
WebDriver Wire協(xié)議是通用的,也就是說不管是FirefoxDriver還是ChromeDriver,啟動之后都會在某一個端口啟動基于這套協(xié)議的Web Service。例如FirefoxDriver初始化成功之后,默認(rèn)會從http://localhost:7055開始,而ChromeDriver 則大概是http://localhost:46350之類的。
接下來,我們調(diào)用WebDriver的任何API,都需要借助一個 ComandExecutor發(fā)送一個命令,實(shí)際上是一個HTTP request給監(jiān)聽端口上的Web Service。在我們的HTTP request的body中,會以WebDriver Wire協(xié)議規(guī)定的JSON格式的字符串來告訴Selenium我們希望瀏覽器接下來做什么事情。
WebDriver 啟動目標(biāo)瀏覽器,并綁定到指定端口。該啟動的瀏覽器實(shí)例,做為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端的這些功能是如何實(shí)現(xiàn)的呢?答案是瀏覽器實(shí)現(xiàn)了webdriver的統(tǒng)一接口,這樣client就可以通過統(tǒng)一的restful的接口去進(jìn)行瀏覽器的自動化操作。目前webdriver支持ie, chrome, firefox, opera等主流瀏覽器,其主要原因是這些瀏覽器實(shí)現(xiàn)了webdriver約定的各種接口。
可以更通俗的理解:由于客戶端腳本(java,python,ruby)不能直接與瀏覽器通信,這時候可以把WebService當(dāng)做一個翻譯器,它可以把客戶端代碼翻譯成瀏覽器可以識別的代碼(比如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)的理解。
舉個實(shí)際的例子:
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是實(shí)現(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端的實(shí)現(xiàn)的方法的名稱,這里是get,表示跳轉(zhuǎn)到指定url;sessionId:當(dāng)前session的id;status:請求執(zhí)行的狀態(tài)碼,非0表示未正確執(zhí)行,這里是0,表示一切ok不必?fù)?dān)心;value:請求的返回值,這里返回值為空,如果client調(diào)用title接口,則該值應(yīng)該是當(dāng)前頁面的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端進(jìn)行交互。
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()
# 前進(jìn),要有歷史記錄
chrome_driver.forward()

# 刷新
chrome_driver.refresh()

# 等待10s,更明顯看出效果
sleep(10)
# 關(guān)閉窗口,關(guān)閉當(dāng)前窗口
chrome_driver.close()

# 等待10s,更明顯看出效果
sleep(10)

# 關(guān)閉會話,關(guān)閉瀏覽器,關(guān)閉driver
chrome_driver.quit()
鼠標(biāo)事件






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("設(shè)置") #  對定位到的元素執(zhí)行鼠標(biāo)懸停操作
ActionChains(driver).move_to_element(above).perform()
'''
perform(): 執(zhí)行操作
context_click(): 右擊;
double_click(): 雙擊;
drag_and_drop(): 拖動;
move_to_element(): 鼠標(biāo)懸停
'''
鍵盤事件
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)’)
復(fù)制(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()
瀏覽器標(biāo)簽頁切換
win_sli = driver.window_handles  # 獲取當(dāng)前所有標(biāo)簽頁的句柄

# 循環(huán)所有標(biāo)簽,直到找到標(biāo)題、url、頁面元素相符的標(biāo)簽,就停止切換,停留在當(dāng)前標(biāo)簽頁
for win in win_sli:
    driver.switch_to.window(win)
    # 如果標(biāo)簽頁的標(biāo)題不固定,還可以用網(wǎng)址判斷
    # 如果網(wǎng)址和標(biāo)題都不固定,可以找一個目標(biāo)標(biāo)簽頁獨(dú)有的元素,然后判斷元素是否存在
    if driver.title == "OPMS-項(xiàng)目管理軟件+OA管理軟件+CRM管理軟件":
        break
'''
current_window_handle:獲得當(dāng)前標(biāo)簽頁句柄
window_handles:返回所有便簽頁的句柄
switch_to.window(標(biāo)簽頁句柄):切換到對應(yīng)的標(biāo)簽頁
關(guān)閉標(biāo)簽頁使用 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")

# 對元素進(jìn)行截圖
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
# 確認(rèn)對話框
al.accept()
'''
text:返回 alert/confirm/prompt 中的文字信息
accept():接受現(xiàn)有警告框
dismiss():取消現(xiàn)有警告框
send_keys(“haha”):發(fā)送文本至警告框
'''




作者: Python測試社區(qū)


歡迎關(guān)注微信公眾號 :Python測試社區(qū)