元素等待
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的页面
<!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可能存在多个