概述
selenium是一個模擬控制瀏覽器操作的自動化庫,它可以做到元素定位,鼠標事件,瀏覽器事件,js腳本執行等操作
與request不同的是,request是單獨請求一個http,而selenium則是以瀏覽器方式加載整個頁面流,所以那些異步的請求也不用像request一樣去分析接口,一切都像瀏覽器一樣,所見即所得。
優點是:
1.所見即所得,不用考慮cookie,ajax,重定向等等,方便數據的查取
2.平時在我們在瀏覽器上做的操作(鼠標,瀏覽器操作等),基本都可以用這個實現,並且步驟動態可視
3.多平台支持,不僅語言多平台支持,支持瀏覽器driver也很多
缺點是:
1.慢,由於加載了整個頁面的數據流,資源開銷大,所以對於只想獲取關鍵數據來說肯定沒有請求接口來的快
2.不穩定,腳本維護成本高等,比如你用xpath去找元素,但是前端改其他問題影響到了你這個元素的路徑,那么這個腳本就gg
主要作用:
1.用於前端自動化測試,總的來說算集成測試,更關注用戶端的測試
2.模擬登錄等,爬蟲的模擬登錄常用到,同時使用這種時要開開發者模式,因為已經有很多網站能識別了
3.個人辦公用途,減少重復勞動力。舉個栗子:百度雲離線下載多個鏈接
安裝
庫安裝
pip install selenium
WebDriver安裝
WebDriver是W3C的一個標准,由Selenium主持,主要目的就是通過這套WebDriverAPI控制你電腦上的瀏覽器,相當於一個selenium與瀏覽器之間的驅動,需要注意的是,不同瀏覽器,需要安裝不同的WebDriver,常見的如下
其中PhantomJS是一個無窗口的WebDriver,現在已經停更了
根據你電腦所裝瀏覽器版本來安裝WebDriver(至少需要大版本相同,不然會有一些問題),安裝WebDriver很簡單,將可執行文件放到腳本目錄或者python安裝目錄即可
WebDriver
創建WebDriver對象
創建WebDriver對象,相當於啟動了瀏覽器
#導入webdriver模塊 from selenium import webdriver #創建對象,根據你選擇的瀏覽器創建 driver = webdriver.Chrome() driver = webdriver.Firefox() driver = webdriver.Ie() driver = webdriver.Edge() driver = webdriver.Opera() driver = webdriver.PhantomJS()
WebDriver對象操作
對WebDriver對象的操作可以抽象成你怎么去控制瀏覽器,主要方法有:
1.訪問URL
driver.get("http://www.python.org")
2.窗口大小調整
#設置寬800px 高600px driver.set_window_size(800,600) #設置最大,最小 driver.maximize_window() driver.minimize_window()
3.刷新頁面
driver.refresh()
4.前進后退
driver.forward()
driver.back()
5.關閉瀏覽器或窗口
#關閉瀏覽器 driver.quit() #關閉窗口 driver.close()
6.返回當前的一些屬性
#當前url driver.current_url #返回窗口句柄 driver.current_window_handle #當前 driver.window_handles #所有 #返回title driver.title
7.查找元素,返回Element對象,之后會詳細講
find_element_by_name()
find_element_by_id()
find_element_by_xpath()
find_element_by_link_text()
find_element_by_partial_link_text()
find_element_by_tag_name()
find_element_by_class_name()
find_element_by_css_selector()
8.切換窗口
driver.switch_to_window(handle)
9.切換frame
#切換框架,直接輸入iframe的name或id屬性,或者傳入定位的元素 driver.switch_to_frame(frame_reference)
10.截圖保持為文件
#img_path_name為文件路徑,只支持.png格式,文件名注意帶上后綴,如“/Screenshots/foo.png” driver.get_screenshot_as_file(img_path_name)
11.執行js
#簡單執行 driver.execute_script(script, *args) -script:要執行的JavaScript。 -*args:JavaScript的所有適用參數。 #異步執行 driver.execute_async_script(script, *args)
12.操作cookie
#獲取cookies driver.get_cookies() #添加cookie driver.add_cookie(cookie_dict) #刪除cookie driver.delete_all_cookies() #所有 driver.delete_cookie(name) #一個,指明key
元素Element
查找元素Element
在我們使用driver.get(url)方法后,driver會加載整個頁面,如果我們要操作比如點擊頁面中的某個元素,則首先需要定位到這個元素,再進行操作
注意的是這部分需要HTML CSS XPATH基礎,不熟悉的可以查看W3C教程,這里不做多訴
示例
<html> <body> <h1>Welcome</h1> <p class="content">Site content goes here.</p> <form id="loginForm"> <input name="username" type="text" /> <input name="password" type="password" /> </form> <a href="continue.html">Continue</a> </body> <html>
1.通過id屬性定位
driver.find_element_by_id(‘loginForm’) #定位<form id="loginForm">
2.通過name屬性定位
driver.find_element_by_name(‘username’) #定位<input name="username" type="text" />
3.通過class名定位
driver.find_elements_by_class_name(‘content’) #定位<p class="content">Site content goes here.</p>
4.通過TagName標簽名定位
driver.find_element_by_tag_name(‘input’) #定位<input name="username" type="text" />,如果匹配了多個,只選第一個
5.通過link text定位,就是通過a標簽的text內容定位
driver.find_elements_by_link_text(‘Continue’) #全匹配 driver.find_element_by_partial_link_text(‘Cont’) #部分text匹配 #定位<a href="continue.html">Continue</a>
6.通過xpath定位
driver.find_element_by_xpath("//from[input/@name='username']") #定位<input name="username" type="text" />
簡單說一句:/ 代表選取直接子節點,// 代表選擇所有子孫節點,. 代表選取當前節點,.. 代表選取當前節點的父節點,@ 則是加了屬性的限定並選取匹配屬性的特定節點,[]是謂語的意思。
7.通過css選擇器定位
driver.find_element_by_css_selector('p.content') #定位<p class="content">Site content goes here.</p>
8.定位多個元素
將1~7中的find_element_by_xxx改成find_elements_by_xxx則可以返回所有匹配的元素為list
driver.find_elements_by_tag_name(‘input’) 定位[<input name="username" type="text" /> <input name="password" type="password" />]
9.串聯查找
Element對象也是有find_element_by_xxx這些方法的,所以可以在第一次定位的元素下查找子節點等
driver.find_element_by_id(‘loginForm’).find_element_by_name(‘username’)
10.簡潔方法
find_element(by='id', value=None)與find_elements(by='id', value=None)實際是實現find_element_by_xxx這個的底層實現,只是簡潔些,當然我們也可以用
#導入By模塊,實際里面就是id,class,name這些常量 from selenium.webdriver.common.by import By driver.find_element(By.NAME,username)
元素Element事件
Element對象有一系列的方法,來讓我們操作定位的元素
1.Element.click() 點擊元素
driver.find_elements_by_link_text(‘Continue’).click()
2.輸入文本
#有些輸入框中原有的文本不會被自動清除掉,需要使用clear()方法清除 driver.find_element_by_name(‘username’).clear() #輸入內容 driver.find_element_by_name(‘username’).send_keys("username")
3.獲取參數
#獲取對應特性值 Element.get_attribute(name) #獲取對應屬性值 Element.get_property(name) #property是DOM中的屬性,是JavaScript里的對象;attribute是HTML標簽上的特性,它的值只能夠是字符串。一般用attr就行 #獲取當前元素的內容 Element.text #獲取當前元素標簽名 Element.tag_name #獲取當前元素尺寸 Element.size #獲取當前元素坐標 Element.location
4.判斷方法
#判斷當前元素是否可見 Element.is_displayed() #判斷當前元素是否被啟用 Element.is_enabled() #判斷當前元素是否被選中 Element.is_selected()
等待
現在的網頁,基本都是使用ajax異步的加載各種資源的,所以可能我們需要定位的元素不會第一時間就加載出來,這時候是無法定位的,也就會拋出異常。而解決這個問題的方法,就是等待。
1.硬性等待
使用time.sleep(sec)實現,需要自己估計網頁加載的時間,硬性地等待,無論網頁加載快慢,都會強制等待這么多時間
import time time.sleep(10)
2.顯式等待
就是設定一個條件,同時設置一個時間,在這個時間范圍內,如果網頁出現符合的條件,就不等待繼續執行,如果沒有則循環直到超時報錯
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Firefox() driver.get("http://somedomain/url_that_delay_loading") try: element = WebDriverWait(driver,10).until( EC.presence_of_element_located((By.ID,"myDynamicElement")) ) finally: driver.quit()
這段代碼主要講的是:
- 實例化WebDriverWait類,傳入driver與最大等待時長,默認poll_frequency(掃描頻率)為500毫秒
- until()是WebDriverWait類的一個方法,參數是一個等待條件(expected_conditions),如果滿足等待條件,則WebDriverWait類停止等待,並且返回expected_conditions的值,否則當等待時間到將拋出TimeoutException異常
- 除了until()還有個until_not(),看語義就明白
- 等待條件(expected_conditions)如果成功則返回element對象,或有些是返回布爾值,或者其它不為null的值
等待條件(expected_conditions)內置的方法主要有:
title_is : #驗證 driver 的 title 是否與傳入的 title 一致,返回布爾值 title_contains : #驗證 driver 的 title 中是否包含傳入的 title,返回布爾值 presence_of_element_located :# 驗證頁面中是否存在傳入的元素,傳入元素的格式是 locator 元組,如 (By.ID, "id1"),返回element對象 visibility_of_element_located : #驗證頁面中傳入的元素( locator 元組格式 )是否可見,這里的可見不僅僅是 display 屬性非 None ,還意味着寬高均大於0,返回element對象或false visibility_of : #驗證頁面中傳入的元素( WebElement 格式 )是否可見。返回element對象或false presence_of_all_elements_located : #驗證頁面中是否存在傳入的所有元素,傳入元素的格式是 locator 元組構成的 list,如 [(By.ID, "id1"), (By.NAME, "name1"),返回element或false text_to_be_present_in_element : #驗證在指定頁面元素的text中是否包含傳入的文本,返回布爾值 text_to_be_present_in_element_value : #驗證在指定頁面元素的value中是否包含傳入的文本,返回布爾值 frame_to_be_available_and_switch_to_it : #驗證frame是否可切入,傳入 locator 元組 或 WebElement,返回布爾值 invisibility_of_element_located : #驗證頁面中傳入的元素( locator 元組格式 )是否可見,返回布爾值 element_to_be_clickable : #驗證頁面中傳入的元素( WebElement 格式 )是否點擊,返回element staleness_of : #判斷傳入元素(WebElement 格式)是否仍在DOM中,返回布爾值 element_to_be_selected : #判斷傳入元素(WebElement 格式)是否被選中,返回布爾值 element_located_to_be_selected :# 判斷傳入元素(locator 元組格式)是否被選中,返回布爾值 element_selection_state_to_be :# 驗證傳入的可選擇元素(WebElement 格式)是否處於某傳入狀態,返回布爾值 element_located_selection_state_to_be : #驗證傳入的可選擇元素(WebElement 格式)是否處於某傳入狀態,返回布爾值 alert_is_present : #驗證是否有 alert 出現。返回alert對象
3.隱式等待
一種全局的設置,設置一個最大時長,如果定位的元素沒有出現就會循環的查詢直到超時或者元素出現,相比於硬性等待,這個更加彈性,元素出現了就不會等待了
rom selenium import webdriver driver = webdriver.Firefox() driver.implicitly_wait(10) # seconds driver.get("http://somedomain/url_that_delays_loading") myDynamicElement = driver.find_element_by_id('myDynamicElement')
行為鏈
ActionChains可以完成簡單的交互行為,例如鼠標移動,鼠標點擊事件,鍵盤輸入,以及內容菜單交互。這對於模擬那些復雜的類似於鼠標懸停和拖拽行為很有用
使用方法:
實例化一個ActionChains對象並在對象上調用行為方法時,這些行為會存儲在ActionChains對象的一個隊列里。只有調用perform()時,這些動作就以他們隊列的順序來觸發
導入類
from selenium.webdriver import ActionChains
鏈式模型操作:
menu = driver.find_element_by_css_selector(".nav") hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1") ActionChains(driver).move_to_element(menu).click(hidden_submenu).perform()
隊列順序操作:
menu = driver.find_element_by_css_selector(".nav") hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1") actions = ActionChains(driver) actions.move_to_element(menu) actions.click(hidden_submenu) action.perform()
主要的行為方法有
click(on_element=None) #點擊一個元素。參數:on_element:要點擊的元素,如果是None,點擊鼠標當前的位置 click_and_hold(on_element=None) #鼠標左鍵點擊一個元素並且保持。參數:on_element:同click()類似 double_click(on_element=None) #雙擊一個元素 drag_and_drop(source, target) #鼠標左鍵點擊source元素,然后移動到target元素釋放鼠標按鍵 drag_and_drop_by_offset(source, xoffset,yoffset) #拖拽目標元素到指定的偏移點釋放。參數: source:點擊的參數 xoffset:X偏移量 * yoffset:Y偏移量 key_down(value,element=None) #只按下鍵盤,不釋放。我們應該只對那些功能鍵使用(Contril,Alt,Shift)。參數: value:要發送的鍵,值在Keys類里有定義 element:發送的目標元素,如果是None,value會發到當前聚焦的元素上 key_up(value,element=None) #釋放鍵。參考key_down的解釋 move_by_offset(xoffset,yoffset) #將當前鼠標的位置進行移動 move_to_element(to_element) #把鼠標移到一個元素的中間 move_to_element_with_offset(to_element,xoffset,yoffset) #鼠標移動到元素的指定位置,偏移量以元素的左上角為基准。參數: to_element:目標元素 xoffset:要移動的X偏移量 * yoffset:要移動的Y偏移量 perform() #執行所有存儲的動作 release(on_element=None) #釋放一個元素上的鼠標按鍵 send_keys(*keys_to_send) #向當前的焦點元素發送鍵 send_keys_to_element(element,*keys_to_send) #向指定的元素發送鍵
參考的key值在這里
彈窗操作
目前主流彈窗就三種,alert,window,div封裝的
alert彈窗
alert彈窗主要是js中alert()、confirm()、prompt()方法實現的,雖然這三種在js中不同,但對selenium都可以統一實例化Alert對象處理,首先查看Alert對象的主要方法
#接受和忽略彈框: Alert(driver).accept() Alert(driver).dismiss() #prompt里輸入字符: Alert(driver).send_keys("text") #讀取prompt的提示字符: Alert(driver).text #向一個認證的對話框發送用戶名和密碼,會自動點擊確認 Alert(driver).authenticate('user','passwd')
對於彈窗生成Alert對象主要有兩種方法
1.使用driver的API切換至彈窗操作
alert = driver.switch_to_alert() #底層實際就是Alert(driver),返回Alert對象
2.直接使用Alert類實例化
from selenium.webdriver.common.alert import Alert alert = Alert(driver)
window類型
window類型實際就是那種點擊界面元素后,瀏覽器新開的一個窗口,我們可以用driver的API直接切換到這個窗口進行一般的定位元素那些操作
#選擇對應的window_handle切換 driver.switch_to_window(window_handle) #window_handle獲取 driver.current_window_handle driver.window_handles
div封裝的
div封裝的彈窗就是使用瀏覽器F12查看HTML源代碼時,彈窗的代碼由div標簽封裝在頁面中,所以這種彈窗可以直接find_element_by_xxx直接定位
可能還有網頁中使用frame標簽的,這就需要先切換到新的frame,上面driver的方法有介紹
如果對JavaScript熟悉的,這些彈窗都可以用js處理
參考:
https://python-selenium-zh.readthedocs.io/zh_CN/latest
https://selenium-python.readthedocs.io/api.html