1. 程式人生 > 實用技巧 >五、元素等待/三大切換

五、元素等待/三大切換

元素等待

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可能存在多個