五、元素等待/三大切換
元素等待
CPU的執行速度遠遠大於網頁的頁面載入速度,會導致定位不到元素,所以要進行元素等待。
一、強制等待
time.sleep( ) 單位:秒
缺點:時間不好控制
需要等待的時候加time.sleep( ),等待n秒後進行下一步操作。無論條件成立與否,都要等待到時間後才能進行下一步操作
import time from selenium import webdriver driver = webdriver.Chrome() driver.get("http://www.baidu.com") e = driver.find_element_by_id("kw") e.send_keys("檸檬班") # 點選百度一下 driver.find_element_by_id("su").click() # 強制等待元素載入0.5秒 time.sleep(0.5) driver.find_element_by_link_text("lemon.ke.qq.com/").click()
二、隱形等待
給一個超時時間,如果在超時時間之內能夠找到,就直接返回元素,如果超時了,就報錯
--全域性設定,設定一次就行
--設定超時時間
--只能用來等待元素
--找不到元素報錯:NoSuchElement
import time from selenium import webdriver driver= webdriver.Chrome() # 隱式等待超時時間,全域性設定。每次查詢自動設定超時20秒 driver.implicitly_wait(20) driver.get("http://www.baidu.com") e = driver.find_element_by_id("kw") e.send_keys("檸檬班") # 點選百度一下 driver.find_element_by_id("su").click() driver.find_element_by_link_text("lemon.ke.qq.com/").click()
三、顯性等待
--等待某個元素被點選
--等待某個元素可見
--等待某個視窗被開啟
不是全域性的,每次等待都要單獨設定
找不到元素時報錯:TimeoutException
顯性等待幾個重要的條件:
1.presence_of_element_located(locator) 元素是否出現
2.visibility_of_element_located(locator) 元素是否可見
3.element_to_be_clickable(locator) 元素是否可以被點選
from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions driver = webdriver.Chrome() driver.get("http://www.baidu.com") e = driver.find_element_by_id("kw") e.send_keys("檸檬班") # 點選百度一下 driver.find_element_by_id("su").click() # 顯性等待 # 第一步:設定定時器(每隔0.5秒查詢一次,直到找到元素。poll_frequency可省略-預設是0.5) wait = WebDriverWait(driver,timeout=20,poll_frequency=0.5) # 第二步:設定滿足的條件(可以是任意條件,需要返回True,如果是False進入下一輪詢,直至超時) locator=('xpath','//*[text()="lemon.ke.qq.com/"]') elem = wait.until(expected_conditions.presence_of_element_located(locator=locator)) print(elem.text)
封裝(等待元素被點選)
def wait_element_clikable(locator,driver,timeout = 20,poll = 0.5): """等待元素被點選""" wait = WebDriverWait(driver, timeout=timeout, poll_frequency=poll) elem = wait.until(expected_conditions.element_to_be_clickable(locator=locator)) return elem def wait_elemet_presence(locator,driver,timeout = 20,poll = 0.5): """等待元素出現""" wait = WebDriverWait(driver, timeout=timeout, poll_frequency=poll) elem = wait.until(expected_conditions.presence_of_element_located(locator=locator)) return elem def wait_elemet_visiable(locator,driver,timeout = 20,poll = 0.5): """等待元素可見""" wait = WebDriverWait(driver, timeout=timeout, poll_frequency=poll) elem = wait.until(expected_conditions.visibility_of_element_located(locator=locator)) return elem
等待方式的選擇
--隱式等待:全域性設定,等待查詢元素(第一順位)
--顯性等待:等待元素可以被點選、可見等(第二順位)
--強制等待:多個系統互動的地方
四、總結
1)元素等待
首先用find_element()進行查詢,看看是不是要進行元素等待。(有些元素不需要動態載入的,是不用等待的),如果找不到,用隱性等待。隱性等待找不到,用顯性等待;
顯性等待找不到,要記得切換條件(presence、visible、clickable);還是找不到再用強制等待。
2.元素定位不到的原因有哪些?nosuchelement
①檢查元素定位的方式是否正確
②沒有加元素等待 (除錯的時候直接用強制等待,效果比較明顯)
③檢查有沒有在這個頁面上:有沒有在這個視窗上;是不是在一個iframe中
視窗切換
selenium不會自動進行頁面的跳轉動作,需要手動進行頁面切換後,才能進行新頁面的元素定位
一、視窗切換
視窗切換的函式:driver.switch_to.window(引數)
獲取所有的視窗控制代碼:driver.window_handles
切換到最新跳轉的頁面:driver.window_handles[-1]
from selenium import webdriver driver = webdriver.Chrome() driver.implicitly_wait(5) driver.get("http://www.baidu.com") e = driver.find_element_by_id("kw") e.send_keys("檸檬班") # 點選百度一下 driver.find_element_by_id("su").click() driver.find_element_by_link_text("lemon.ke.qq.com/").click() # 獲取現在的url print(driver.current_url) # 視窗控制代碼 print(driver.window_handles) # 視窗切換 driver.switch_to.window(driver.window_handles[-1]) print(driver.current_url)
二、iframe切換
判斷有沒有iframe:看下面的bar,有沒有iframe,或者兩個html
iframe切換語法:driver.switch_to.frame()
切換到父級iframe:switch_to.parent.frame( )帶iframe的頁面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <p>hello</p> </div> <iframe src="http://www.baidu.com" height="600" width="1300"></iframe> <div> <p>world</p> </div> </body> </html>
from selenium import webdriver driver = webdriver.Chrome() driver.implicitly_wait(5) driver.get("http://localhost:63342/study/Lemon/demohtml.html?_ijt=i5m09icq2rq7g6e7pgfthgcq5b") # 先找到要切換的iframe iframe_elem = driver.find_element_by_xpath('//iframe[@src]') driver.switch_to.frame(iframe_elem) # 定位iframe中百度當中的input kw input_elem = driver.find_element_by_id("kw") input_elem.send_keys("檸檬班") # 點選百度一下 driver.find_element_by_id("su").click() # 定位主頁面的元素,必要切回主頁面 driver.switch_to.default.content() driver.find_element_by_id("hello")
如果主頁面中有一個iframe,iframe中還套有iframe,怎麼辦?
- 先通過xpath找第一次的iframe,再通過xpath找第二層iframe,以此類推。。
在多層iframe中,如何退回到主頁面?
- 通過parent_frame()一層一層退出來。witch_to.parent_frame()
擴充套件:iframe等待
不能使用隱形等待,因為隱形等待只能等待元素,不能等待頁面
強制等待時間不好控制
可以使用顯性等待(自動切換到iframe,不需要手動切換到iframe)
WebDriverWait(driver,timeout=10,poll_frequency=0.5).until(
expected_conditions.frame_to_be_available_and_switch_to_it(iframe_elem)
)
三、alert切換
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <p id="hello" onclick="alertMe()"> hello world </p>
<script> function alertMe(){ alert("this is a alert window!") } </script> </div> </body> </html>
import time from selenium import webdriver driver = webdriver.Chrome() driver.implicitly_wait(5) driver.get("http://localhost:63342/study/Lemon/demohtml.html?_ijt=3mm3fi2qatf20a9rongkmg4it3") driver.find_element_by_id("hello").click() # 切換到alert,點選確定按鈕 e = driver.switch_to.alert time.sleep(5) e.accept()
alert等待的條件:alert_is_present()
from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions #初始化driver瀏覽器物件 driver = webdriver.Chrome() driver.get("http://localhost:63342/study/Lemon/demohtml.html?_ijt=3mm3fi2qatf20a9rongkmg4it3") #id 定位元素learn python,並點選 driver.find_element_by_id("hello").click() # 切換到alert alert_elem = driver.switch_to.alert #顯性等待alert並切換 alert_elem = WebDriverWait(driver,timeout=20,poll_frequency=0.5).until(expected_conditions.alert_is_present()) #點選確定 alert_elem.accept()
總結:
iframe切換需要加引數,alert切換不需要加引數:一個頁面只可能有一個alert,但是iframe可能存在多個