全篇大概10000字(含代碼),建議閱讀時間30min
一、等待機制
如果有一些內容是通過Ajax加載的內容,那就需要等待內容加載完畢才能進行下一步操作。
為了避免人為操作等待,會遇到的問題, selenium將等待轉換為機器去等待,去判斷在什么時間去進行下一步操作。
1.1 頁面級等待機制
定義等待頁面加載完畢的超時時間,默認設置為0表示等待時間不限。
set_page_load_timeout(最長等待秒數)
設置等待超時時間,全局設置,在WebDriver 生命周期內生效
from selenium import webdriverdriver = webdriver.Chrome()
driver.set_page_load_timeout(3)
driver.get("https://www.selenium.dev/")
driver.quit()
等待時間設置為3秒,如果加載時間超過3秒,就會拋出異常。如果在3秒內加載完成,則執行下一行代碼。
1.2元素級等待機制強制等待
也就是說有一些元素需要觸發特定區域后才會顯示,才能進行下一步操作。
這樣就可以使用強制等待方式,通過 time庫來進行等待。
from selenium import webdriver
from selenium.webdriver.common.by import By
import timedriver = webdriver.Chrome()
driver.get("https://www.baidu.com")driver.find_element(By.LINK_TEXT, "登錄").click()
time.sleep(3)
driver.find_element(By.LINK_TEXT, "立即注冊").click()
driver.quit()
不建議使用!
1.3 素級等待機制隱式等待
它是在執行函數時增加一些寬限時間,設置一個最長超出時間,如果在一定時間內元素還是沒有出現,直接拋出異常、
implicitly_wait(等待秒數)
隱式等待
from selenium import webdriver
from selenium.webdriver.common.by import Bydriver = webdriver.Chrome()
driver.implicitly_wait(10)driver.get("https://www.baidu.com")
driver.find_element(By.LINK_TEXT, "登錄").click()
driver.find_element(By.LINK_TEXT, "立即注冊").click()driver.quit()
負作用:
- 檢查某元素是否不存在,等待隱式等待中設置最大時長,減緩測試速度。
- 干擾顯式等待。
1.4 元素及等待機制 顯式等待
指定條件判斷函數,每隔一定時間檢測該條件是否成立。成立就執行下一步,直到超過最大等待時間。
from selenium.webdriver.support.wait import WebDriverWait
導入
WebDriverWait(WebDriver實例, 超時秒數, 檢測時間間隔(可選), 可忽略異常集合(可選))
實例化方法
檢測時間間隔: 調用until 或until_not 中傳入判斷函數的間隔時間,默認0.5秒。
可忽略異常集合:調用until或until_not 中傳入判斷函數,如果拋出集合中定義的異常,代碼不會執行失敗,會繼續正常執行。默認異常是 NoSuchElementException。
until
等待直到條件判斷函數的返回值不為False。
until_not
等待直到條件判斷函數返回值為False,如果拋出可忽略異常,會當做False處理。
使用自定義等待條件函數
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWaitdef registerLinkDisplayed(webDriver):# 檢測是否已經顯示立即注冊鏈接return webDriver.find_element(By.LINK_TEXT, "立即注冊").is_displayed()driver = webdriver.Chrome()
driver.get("https://www.baidu.com")driver.find_element(By.LINK_TEXT, "登錄").click()
# 每間隔0.5秒 去調用判斷函數,條件滿足執行下一行代碼。
WebDriverWait(driver, 10).until(registerLinkDisplayed)
driver.find_element(By.LINK_TEXT, "立即注冊").click()
driver.quit()
使用預定義等待條件函數
from selenium.webdriver.suport import expected_conditions
預定義等待函數
visibility_of_element_located()
判斷目標元素是否處于可見狀態
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditionsdriver = webdriver.Chrome()
driver.get("https://www.baidu.com")driver.find_element(By.LINK_TEXT, "登錄").click()
targetLocator = (By.LINK_TEXT, "立即注冊")
WebDriverWait(driver, 10).until(expected_conditions.visibility_of_all_elements_located(targetLocator))driver.find_element(By.LINK_TEXT, "立即注冊").click()driver.quit()
預定義所有條件等待函數
類別 | 函數名稱 | 參數 | 功能 |
判斷元素的可見性 | visibility_of_element_located | locator(目標元素定位) | 判斷目標元素是否已顯示,如果已顯示,則返回該WebElement對象 |
visibility_of | webElement(目標元素) | 判斷目標元素是否已顯示,如果已顯示,則返回該WebElement對象 | |
visibility_of_all_elements_located | locator(目標元素定位) | 判斷頁面上是否存在一個或多個符合定位的元素,且是否已全部顯示,如果是,則返回WebElement集合 | |
visibility_of_any_elements_located | locator(目標元素定位) | 根據定位判斷頁面上是否存在一個或多個符合定位的元素,元素中是否至少有一個已先睡,如果是,則返回其中已顯示的WebElement集合 | |
invisibility_of_element_located | locator(目標元素定位) | 根據定位判斷目標元素是否未顯示 | |
判斷元素的狀態、文本、值 | element_to_be_clickable | locator(目標元素定位) | 根據定位判斷目標元素是否處于可單擊狀態 |
element_located_to_be_selected | locator(目標元素定位) | 根據定位判斷目標元素是否處于已選中狀態 | |
element_to_be_selected | webElement(目標元素) | 判斷目標元素是否處于已選中狀態 | |
element_located_selection_state_to_be | locator(目標元素定位),is_selected(期望狀態) True(選中) False(未選中) | 根據定位判斷選中狀態是否符合預期 | |
element_selection_state_to_be | webElement(目標元素),is_selected(期望狀態) True(選中) False(未選中) | 判斷目標元素選中狀態是否符合預期 | |
text_to_be_present_in_element | locator(目標元素定位), text(期望包含的文本) | 判斷目標元素的文本是否包含期望的文本 | |
text_to_be_present_in_element_value | locator(目標元素定位),text(期望包含的文本) | 判斷目標元素的value屬性是否已包含期望文本 | |
判斷元素是否存在 | presence_of_element_located | locator(目標元素定位) | 根據定位判斷頁面上是否存在首個符合定位元素,如果有,則返回該WebElement |
presence_of_all_elements_located | locator(目標元素定位) | 根據定位判斷頁面上是否存在一個或多個符合定位元素,如果有,則返回WebElement集合 | |
staleness_of | webElement(目標元素) | 判斷目標元素是否已經從DOM結構上完全消失 | |
判斷瀏覽器窗口、彈框及內嵌網頁 | new_window_is_opened | current_handles(當前的窗口句柄集合) | 判斷是否有新窗口打開,句柄數量是否會在當前句柄集合的基礎上有所基礎 |
number_of_windows_and_switch_to_it | locator(目標元素(IFrame/Frame)定位) | 根據定位判斷是否可以切換到目標元素,如果可以切換,則會直接切換到指定元素(IFrame/Frame)上 | |
alert_is_present | - | 判斷是否已出現瀏覽器彈窗 | |
判斷網頁標題或URL | title_contains | title(期望包含的標題) | 判斷網頁標題是否已包含期望的標題(即是否模糊匹配) |
title_is | title(期望相等的標題) | 判斷網頁標題是否完全等于期望的標題(即是否完全匹配) | |
url_changes | url(當前URL) | 判斷URL是否發生變化,即與當前的URL不相同 | |
url_contains | url(期望包含的URL) | 判斷URL是否已包含期望的URL(即是否模糊匹配) | |
url_matches | pattern(格式表達式) | 判斷URL是否匹配格式表達式(例如正則表達式) | |
url_to_be | url(期望相等的URL) | 判斷URL是否已包含期望的URL(即是否完全匹配) |
3. 其他可選參數設置
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common import exceptionsdriver = webdriver.Chrome()
driver.get("https://www.baidu.com")WebDriverWait(driver, 30, 2, [exceptions.NoSuchElementException, ZeroDivisionError])\.until(lambda p : 3/0, "很明顯, 3是不能除以0的")
1.5 腳本級等待機制
driver.set_script_timeout(最長等待秒數)
為JavaScript設置超時時間
二、對鍵盤和鼠標進行精準模擬
ActionChains 偏向底層的自動化交互方式,實現鼠標移動、單擊、右擊、雙擊、鼠標按下或松開、懸停拖拽、按鍵按下或松開、按組合鍵等復雜的操作。
2.1 ActionChains 操作鏈
from selenium.webdriver.common.action_chains import ActionChains
引入模塊使用庫
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChainsdriver = webdriver.Chrome()
driver.get("https://www.baidu.com")ActionChains(driver).click(driver.find_element(By.LINK_TEXT, "登錄")).perform()
# .click(...) 對操作進行設置,在操作鏈中預約了一個單擊操作,操作對象是登錄。
# .perform() 執行操作鏈中所有操作
driver.quit()
案例:鼠標懸停在設置菜單上,然后再彈出的菜單中選擇搜索設置。最后在彈出的設置面板中按順序進行不顯示、僅繁體中文、顯示、保存設置操作。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()driver.get("https://www.baidu.com")
# move_to_element會將鼠標指針放置在"設置"鏈接上,實現懸停效果
# pause(3) 等待秒
ActionChains(driver).move_to_element(driver.find_element(By.XPATH, "//span[text()='設置']"))\.pause(3).perform()
ActionChains(driver).click(driver.find_element(By.LINK_TEXT, "搜索設置"))\.pause(3).perform()
ActionChains(driver).click(driver.find_element(By.ID, "s1_2"))\.click(driver.find_element(By.ID, "SL_2"))\.click(driver.find_element(By.ID, "sh_1"))\.click(driver.find_element(By.LINK_TEXT, "保存設置"))\.pause(3).perform()driver.quit()
2.2 ActionChains 鼠標與鍵盤操作設置
類別 | 函數名 | 參數 | 功能 |
鼠標按鈕操作設置 | click | element(目標元素,可選) | 單擊目標元素,如果沒有傳入目標元素參數,會單擊當前鼠標指針位置 |
context_click | element(目標元素,可選) | 右擊目標元素,如果沒有傳入目標元素,會右擊鼠標指針位置 | |
double_click | element(目標元素,可選) | 雙擊目標元素,如果沒有傳入目標元素,會雙擊當前鼠標位置 | |
click_and_hold | element(目標元素,可選) | 在目標元素長按鼠標按鈕。如果沒有傳入目標元素,會在當前鼠標位置按下鼠標左鍵 | |
release | element(目標元素,可選) | 在目標元素松開鼠標按鈕。如果沒有傳入目標元素,則會在當前鼠標指針位置按下鼠標左鍵 | |
鼠標移動操作設置 | move_to_element | element(目標元素) | 將鼠標指針移動到目標元素中間 |
move_to_element_with_offset | element(目標元素) ,x坐標,y坐標 | 將鼠標指針移動到相對目標元素的坐標(x,y) | |
move_by_offset | x坐標,y坐標 | 將鼠標移動到相對于目標元素的坐標(x,y) | |
鼠標綜合性操作 | drag_and_drop | sourceElement(被拖放的元素), targetElement(要拖放到的目的地元素) | 在被拖放元素上按下鼠標按鈕,然后移動到目標元素上松開鼠標 |
drag_and_drop_by_offset | sourceElement(被拖放的元素), targetElement(要拖放到目的地元素),x坐標,y坐標 | 在被拖放元素上按下鼠標按鈕,然后移動到相距目標元素坐標x,y,并松開鼠標按鈕 | |
鍵盤按鍵操作設置 | send_keys | keys_to_send(要按的鍵鈕) | 在當前焦點處輸入 |
send_keys_to_element | element(目標元素),keys_to_send(要按的鍵鈕) | 對目標元素按指定鍵 | |
key_down | key(鍵),element(目標元素,可選) | 對目標元素按下指定鍵,如果沒有傳入目標元素,會在當前焦點位置按下指定鍵 | |
key_up | key(鍵),element(目標元素,可選) | 對目標元素松開指定鍵,如果沒有傳入目標元素,則會在當前焦點位置松開指定鍵 | |
等待設置 | pause | seconds(等待秒) | 在指定時間內暫停所有后續操作 |
reset_actions()
清空操作鏈中全部設置
2.3 模擬復雜鍵盤操作
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import timedriver = webdriver.Chrome()
driver.get("https://www.baidu.com")
baiduSearchInput = driver.find_element(By.ID, "kw")baiduSearchInput.send_keys("python")
time.sleep(3)baiduSearchInput.send_keys(Keys.CONTROL, "a")
time.sleep(3)
baiduSearchInput.send_keys(Keys.CONTROL, "x")
time.sleep(3)
baiduSearchInput.send_keys(Keys.CONTROL, "v")
time.sleep(3)
baiduSearchInput.send_keys(Keys.BACKSPACE)
time.sleep(3)
baiduSearchInput.send_keys(Keys.ENTER)
三、操作瀏覽器 Cookie
get_cookies()
獲取所有cookie對象集合
get_cookie(cookie名稱)
根據名稱獲取cookie
from selenium import webdriverdriver = webdriver.Chrome()
driver.get("https://www.baidu.com")# 獲取全部cookies
pageCookies = driver.get_cookies()
for cookie in pageCookies:print(cookie)# 根據名稱獲取cookie
print(driver.get_cookie("BD_HOME"))
3.1 新增和刪除cookie
driver.add_cookie(cookie對象)
新增cookie
from selenium import webdriverdriver = webdriver.Chrome()
driver.get("https://www.baidu.com")
driver.add_cookie({'name': 'MockCookie', 'value': '小那同學'})
可以在瀏覽器F12調試工具中 Application查看當前添加的cookie
delete_all_cookies()
刪除全部 cookie
delete_cookie(cookie名稱)
按名稱刪除指定 cookie
from selenium import webdriverdriver = webdriver.Chrome()
driver.get("https://www.baidu.com")driver.delete_all_cookies()
3.2 對瀏覽窗口或元素截圖
save_screenshot(截圖文件保存路徑)
對瀏覽器截圖
from selenium import webdriverdriver = webdriver.Chrome()
driver.get("https://www.baidu.com")driver.save_screenshot("保存路徑")
3.3 對元素截圖
screenshot(截圖文件路徑)
from selenium import webdriver
from selenium.webdriver.common.by import Bydriver = webdriver.Chrome()
driver.get("https://www.baidu.com")driver.find_element(By.ID, "su").screenshot("圖片地址")
3.4 Selenium操作附加自定義事件
from selenium.webdriver.support.event_firing_webdriver import EventFiringWebDriver
操作添加事件
EventFiringWebDriver(WebDriver實例,AbstractEventListener實例)
AbstractEventListener 抽象類,使用EventFiringWebDriver 需要設定自定義時間監聽器類。
類需要繼承 AbstractEventListener類。
類別 | 函數名 | 參數 | 描述 |
瀏覽器級別 | before_navigate_to(url, driver) | url:跳轉的目標URL driver:當前WebDriver實例 | 導航前事件,定義頁面發生跳轉前需要執行的代碼 |
after_navigate_to(url, driver) | url: 跳轉的目標URL driver:當前WebDriver實例 | 導航后事件,定義頁面發生跳轉后需要執行的代碼 | |
before_navigate_back(driver) | driver:當前WebDriver實例 | 瀏覽器后退前事件,定義瀏覽器在執行后退后需要執行的代碼 | |
after_navigate_forward(driver) | driver: 當前WebDriver實例 | 瀏覽器前進事件,定義瀏覽器在執行前進操作后需要執行的代碼 | |
after_navigate_forward(driver) | driver: 當前WebDriver實例 | 瀏覽器前進后事件,定義瀏覽器在執行關閉操作前需要執行的代碼 | |
before_close(driver) | driver: 當前WebDriver實例 | 瀏覽器關閉后事件,定義瀏覽器在執行關閉操作后需要執行的代碼 | |
元素級 | before_find(by, value, driver) | by: 當前使用的查找條件類型 value:當前使用的查找值 driver: 當前WebDriver實例 | 查找元素前事件,定義Selenium在查找元素前需要執行的代碼 |
after_find(by, value, driver) | by: 當前使用的查找條件類型 value:當前使用的查找值 driver: 當前WebDriver實例 | 找到元素后事件,定義Selenium在找到元素后需要執行的代碼 | |
before_click(element, driver) | element: 要操作的元素 driver: 當前WebDriver實例 | 單擊元素前事件,定義Selenium在單擊元素前需要執行的代碼 | |
after_click(element, driver) | element: 要操作的元素 driver:當前WebDriver實例 | 單擊元素后事件,定義Selenium在單擊元素后需要執行的代碼 | |
before_change_value_of(element, driver) | element: 要操作的元素 driver:當前WebDriver實例 | 元素值變更前事件,定義Selenium更改元素需要執行的代碼 | |
after_change_value_of(element, driver) | element: 要操作的元素 driver: 當前WebDriver實例 | 元素值變更后事件,定義Selenium更改元素值后需要執行的代碼 | |
腳本級 | before_execute_script(script, driver) | script: 要執行的腳本 driver: 當前WebDriver實例 | 腳本執行前事件,定義腳本執行前需要執行的腳本 |
after_execute_script(script, driver) | script:要執行的腳本 driver:當前WebDriver實例 | 腳本執行后事件,定義腳本執行后需要執行的代碼 | |
異常或退出 | on_exception(exception, driver) | exception: 拋出的異常 driver:當前WebDriver實例 | 異常事件,定義在Selenium操作發生異常時需要執行的代碼 |
before_quit(driver) | driver:當前WebDriver實例 | WebDriver退出會話前事件,定義在退出會話前需要執行的代碼 | |
after_quit(driver) | driver: 當前webDriver實例 | WebDriver退出會話后事件,定義在退出會話后需要執行的代碼 |
四、瀏覽器啟動參數設置
4.1 WebDriver 實例化參數
driver = webdriver.Chrome()
默認實例化沒有參數
4.2 瀏覽器設置參數
options
啟動選項,用于設置瀏覽器
desired_capabilities
類似于options, 在遠程運行系統補丁或瀏覽器不定的情況下使用 desired_capabilities,推薦使用 options參數
chrome_options
等同于options參數,已過時不推薦使用
4.3 瀏覽器驅動程序設置參數
executable_path
瀏覽器驅動程序路徑,沒有指定,默認使用環境變量中的路徑。
service_args
瀏覽器驅動程序參數。瀏覽器不同,參數也可能不相同。
port
驅動程序啟用端口號,默認使用任意閑置端口號。
service_log_path
驅動程序存放日志文件地址。
4.4 selenium與瀏覽器驅動程序連接參數
keep-alive
表示與ChromeDriver連接時,是否帶上HTTP請求頭Connecton,默認值為True。
4.5 JavaScript 進行深度操作
雖然Selenium有豐富的操作,但是有一些場景可能需要使用JavaScript進行擴展。
webdriver.execute_script("js腳本", 自定義參數集(可選))
執行同步腳本
webdriver.execute_async_script("js腳本", 自定義參數集(可選))
執行異步腳本
不建議使用Js去執行selenium已經存在的內容。