WebDriver工作原理
- 對於每一條Selenium腳本,一個http請求會被創建並發送給瀏覽器的驅動
- 瀏覽器驅動軸包含了一個HTTP Server,用來接收這些http請求
- HTTP Server接收到請求后根據請求來具體操控對應的瀏覽器
- 瀏覽器執行具體的測試步驟
- 瀏覽器將步驟執行結果返回給HTTP Server
- HTTP Server又將結果返回給Selenium的腳本,如果是錯誤的http代碼我們就會在控制台看到對應的報錯信息
WebDriver的協議
- WebDriver使用的協議是:JSON Wire protocol
- 通信的數據格式是JSON
WebDriver的屬性
| 屬性 | 屬性描述 |
| driver.name | 瀏覽器名稱 |
| driver.current_url | 當前url |
| driver.title | 當前頁面標題 |
| driver.page_source | 當前頁面源碼 |
| driver.current_window_handle | 窗口句柄(相當於一個tab) |
| driver.window_handles | 當前窗口所有句柄 |
WebDriver方法
| 方法 | 方法描述 |
| driver.back() | 瀏覽器后退 |
| driver.forward() | 瀏覽器前進 |
| driver.fresh() | 瀏覽器刷新 |
| driver.close() | 關閉當前窗口 |
| driver.quit() | 退出瀏覽器 |
| driver.switch_to.frame() | 切換到frame |
| driver.switch_to.alert | 切換到alert |
| driver.switch_to.active_element | 切換到活動元素 |
| driver.switch_to.window | 切換窗口 |
WebElement屬性
當我們使用WebDriver的find方法定位到元素后,會返回一個WebElement對象,該對象用來描述Web頁面上的一個元素.WebElement的常用屬性和方法見下表
| 屬性 | 屬性描述 |
| id | 標識 |
| size | 寬高 |
| rect | 寬高和坐標 |
| tag_name | 標簽名稱 |
| text | 文本內容 |
WebElement方法
| 方法 | 方法描述 |
| send_keys() | 輸入內容 |
| clear() | 清空內容 |
| click() | 單擊 |
| get_attribute() | 獲得屬性值 |
| is_selected() | 是否被選中 |
| is_enabled() | 是否可用 |
| is_displayed() | 是否顯示 |
| value_of_css_property() | css屬性值 |
操作下拉列表
處理下拉列表,需要用到selenium中的一個工具類Select,工具位置 from selenium.webdriver.support.select import Select,使用方法
def test_select(self): se = self.driver.find_element_by_id('province') select =Select(se) select.select_by_index(2) sleep(2) select.select_by_value('bj') sleep(2) select.select_by_visible_text('上海')
select常見方法
| 方法/屬性 | 描述 |
| select_by_value() | 根據源碼value選擇 |
| select_by_index() | 根據索引選擇 |
| select_by_visible_text() | 根據文本選擇 |
| deselect_by_value() | 根據源碼value反選 |
| deselect_by_index() | 根據索引反選 |
| deselect_by_visible_text() | 根據文本反選 |
| deselect_all | 反選所有 |
| options | 返回包含所有選項的列表 |
| all_selected_options | 所有已選中選項 |
| first_selected_option | 第一個選擇選項 |
處理彈框
頁面上的彈框有三種
- alert:用來提示
- confirm:用來確認
- prompt:輸入內容
| 方法/屬性 | 描述 |
| accept() | 接受 |
| dismiss() | 取消 |
| text | 彈框的文本 |
| send_keys | 輸入內容 |
selenium的三種等待方式
- time.sleep(sec) 固定等待,不推薦實際測試時使用,可以用來調試
- implicitly_wait 如果某些元素不是立即可用的,隱式等待是告訴WebDriver去等待一定的時間后去查找元素。默認等待時間是0秒,一旦設置該值,隱式等待是設置該WebDriver的實例的生命周期
- WebDriverWait 顯式等待是你在代碼中定義等待一定條件發生后再進一步執行你的代碼,推薦用此方法
顯式等待使用方法
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
def test_wait(self):
wait = WebDriverWait(self.driver, 2)
wait.until(expected_conditions.title_contains('百度一下'))
self.driver.find_element_by_id('kw').send_keys('selenium')
WebDriverWait參數:
- driver:傳入WebDriver實例,即我們上例中的driver
- timeout:超時時間,等待的最長時間
- poll_frequency:調用until或until_not中的方法的間隔時間,默認是0.5秒
- ignored_exceptions:忽略的異常,如果在調用until或until_not的過程中拋出這個元組中的異常,則不中斷代碼,繼續等待,如果拋出的是這個元組外的異常,則中斷代碼,拋出異常。默認只有NoSuchElementException。
這個模塊中,一共只有兩種方法 until 與 until_not:
- until:當某元素出現或什么條件成立則繼續執行
- until_not:當某元素消失或什么條件不成立則繼續執行
until 與 until_not 參數如下:
- method:在等待期間,每隔一段時間調用這個傳入的方法,直到返回值不是False
- message:如果超時,拋出TimeoutException,將message傳入異常
WebDriverWait的17種等待條件
| 條件 | 描述 | 返回值 |
| titile_is | 判斷title,是否出現 | 布爾 |
| title_contains | 判斷title,是否包含某些字符 | 布爾 |
| presence_of_element_located | 判斷某個元素是否被加到了dom樹里, 並不代表該元素一定可見 |
WebElement |
| visibility_of_element_located | 判斷某個元素是否被加到了dom樹里, 並且可見,寬和高都大於0 |
WebElement |
| visibility_of | 判斷元素是否可見,如果可見就返回這個元素 | WebElement |
| presence_of_all_element_located | 判斷是否至少有1個元素存在於dom樹中 | 列表 |
| visibility_of_any_element_located | 判斷是否至少有1個元素在頁面中可見 | 列表 |
| text_to_be_present_in_element | 判斷指定的元素中是否包含了預期的字符串 | 布爾 |
| text_to_be_present_in_element_value | 判斷指定元素的屬性值中是否包含了預期的 字符串 |
布爾 |
| frame_to_be_available_and_switch_to_it | 判斷frame是否可以switch進去 | 布爾 |
| invisibility_of_element_located | 判斷某個元素是否存在於dom或不可見 | 布爾 |
| element_to_be_clickable | 判斷某個元素中是否可見並且是enable的,代表可點擊 | 布爾 |
| staleness_of | 等待某個元素從dom樹中移除 | 布爾 |
| element_to_be_selected | 判斷某個元素是否被選中了,一般用在下拉列表 | 布爾 |
| element_selection_state_to_be | 判斷某個元素的選中狀態是否符合預期 | 布爾 |
| element_located_selection_state_to_be | 判斷某個元素的選中狀態是否符合預期 | 布爾 |
| alert_is_present | 判斷頁面上是否存在alert | alert |
Selenium鼠標和鍵盤事件
selenium中的鼠標和鍵盤事件被封裝在ActionChains類中,正確的使用方法是:
ActionChains(driver).click(button).perform()
ActionChains常用方法:
| 方法 | 方法描述 |
| click(on_element=None) | 點擊鼠標左鍵 |
| click_and_hold(on_element=None) | 點擊鼠標左鍵,不松開 |
| context_click(on_element=None) | 點擊鼠標右鍵 |
| double_click(on_element=None) | 點擊鼠標左鍵 |
| drag_and_drop(source,target) | 拖拽到某個元素然后松開 |
| drag_and_drop_by_offset(source,xoffset,yoffset) | 拖拽到某個坐標然后松開 |
| key_down(value,element=None) | 按下鍵盤上的某個鍵 |
| key_up(value,element=None) | 松開某個鍵 |
| move_by_offset(xoffset,yoffset) | 鼠標送當前位置移動到某個坐標 |
| move_to_element(to_element) | 鼠標移動到某個元素 |
| move_to_element_with_offset(to_element,xoffset,yoffset) | 移動到某個元素(左上角坐標)多少距離的位置 |
| perform() | 執行鏈中所有動作 |
| release(on_element=None) | 在某個元素位置松開鼠標左鍵 |
| send_keys(*keys_to_send) | 發送某個鍵到當前焦點的元素 |
| send_keys_to_element(element,*keys_to_send) | 發送某個鍵到指定元素 |
代碼演示
def test_mouse(self): btn=self.driver.find_element_by_xpath('/html/body/form/input[2]') #雙擊 ActionChains(self.driver).double_click(btn).perform() sleep(2) btn = self.driver.find_element_by_xpath('/html/body/form/input[3]') #單擊 ActionChains(self.driver).click(btn).perform() sleep(2) btn = self.driver.find_element_by_xpath('/html/body/form/input[4]') #右擊 ActionChains(self.driver).context_click(btn).perform() sleep() def test_key(self): self.driver.get('http://www.baidu.com') kw=self.driver.find_element_by_id('kw') kw.send_keys('selenium') #按下control+a全選 kw.send_keys(Keys.CONTROL,'a') sleep(2) # 按下control+x剪切 kw.send_keys(Keys.CONTROL,'x') sleep(2) # 按下control+v粘貼 kw.send_keys(Keys.CONTROL,'v') sleep(2)
Selenium屏幕截圖
WebDriver內置了一些在測試中捕獲屏幕並保存的方法
| 方法 | 方法描述 |
| save_screenshot(filename) | 獲取當前屏幕截圖並保存當當前目錄 |
| get_screenshot_as_base64() | 獲取當前屏幕截圖base64編碼字符串 |
| get_screenshot_as_file(filename) | 獲取當前的屏幕截圖,使用完整的路徑 |
| get_screenshot_as_png() | 獲取當前屏幕截圖的二進制文件數據 |
代碼示例
def test(self): self.driver.find_element_by_id('kw').send_keys('selenium') self.driver.find_element_by_id('su').click() sleep(2) self.driver.get_screenshot_as_file('d:/baidu.png') self.driver.quit()
Selenium定位frame ifame
frame標簽有frameset,frame,iframe三種,framset跟其他普通標簽沒有區別,不會影響到正常的定位,而frame與iframe堆selenium定位而言是一樣的,selenium有一組方法對frame進行操作.
| 方法 | 方法描述 |
| switch_to_frame(reference) | 切換frame,,reference是傳入的參數,用來定位frame,可以傳入id,name,index 以及selenium的WebDriver對象 |
| switch_to.default_content() | 返回主文檔 |
| switch_to.parent_frame() | 返回父文檔 |
時間控件操作
通過js腳本實現
driver.get("https://www.12306.cn/index/") js = "document.getElementById('train_date').removeAttribute('readonly')" driver.execute_script(js) driver.find_element_by_id("train_date").clear() driver.find_element_by_id("train_date").send_keys("2020-10-16")
