在页面的操作过程当中,都需要适当的等待。特别是: 候【发生了页面切换的时候】。而我们接下来的操作都是在变化的内容上。 代码就要等等页面的加载,等等页面的渲染。代码是非常快的,页面加载跟不 上,就需要等待。
三大等待
面试题:selenium的等待方式有哪些?隐性和显性的区别是什 么?
隐式等待:
1、如果超过隐式等待的设置时间还是找不到元素,就会抛出了 NoSuchElementException-找不到元素异常
2、全局生效,只需要设置一次,之后通过find_element去找元素都会有隐 式等待的效果
3、放置的位置,一般我们会将其放置到driver的初始化之后
4、等待条件的区别,只能等待元素存在这一个条件
显式等待
1、如果超过显式等待的设置时间还是找不到元素,就会抛出了 TimeoutException-超时异常
2、局部生效的,只能针对单个元素生效
3、设置的时候是针对单个元素的,并不是全局的
5、等待更多丰富的条件:等待元素可见、可被点击、等待元素存在...
等待的方式有三种:强制等待,隐形等待,显性等待。
1、sleep(秒) -- 强制等待
- 优点:使用简单
- 缺点:等待时间把握不准,容易造成时间浪费或者等待时间不足
# import time from time import sleep from selenium import webdriver from selenium.webdriver.common.by import Bydriver = webdriver.Chrome() driver.maximize_window() driver.get('https://www.baidu.com') driver.find_element(By.ID,'kw').send_keys('菜鸟教程') driver.find_element(By.ID,'su').click() # 代码速度太快了,页面加载需要时间,让我们代码等待一会儿 # time.sleep(2) sleep(2) driver.find_element(By.PARTIAL_LINK_TEXT,' - 学的不仅是技术,更是梦想!').click() sleep(3) driver.quit()
2、智能等待
-- 在指定的时间内,什么时候【条件】成立了,什么时候就不等了。
2.1 隐性等待: driver.implicitly_wait(超时时长-秒)
- 条件:等待一个元素被找到。 找元素都是从html当中去找。find_element, 在html当中是存在的。
- 特征:在一个浏览器会话当中只需要被调用一次,所有的find_element都 可以应用。
""" 智能等待: driver.implicitly_wait() : 括号里写上最长等待时间""" # import time from time import sleep from selenium import webdriver from selenium.webdriver.common.by import Bydriver = webdriver.Chrome() # 隐式等待 driver.implicitly_wait(15) driver.maximize_window() driver.get('https://www.baidu.com') driver.find_element(By.ID,'kw').send_keys('菜鸟教程') driver.find_element(By.ID,'su').click() # 代码速度太快了,页面加载需要时间,让我们代码等待一会儿 driver.find_element(By.PARTIAL_LINK_TEXT,' - 学的不仅是技术,更是梦想!').click()driver.quit()
如果超时时长以内没有找着元素,就会抛异常:NosuchElementException的找不到元素的异常。
- 优点:全局应用,它适用于WebDriver会话期间中所有查找的Web元素 (通过findelement方法)
- 缺点:它只支持单一条件:元素存在;只能等待元素存在,不能适用条件 更复杂的情况,如:元素可点击、元素可见
2.2 显性等待: 多个条件 + 等待时长 ==条件更多,更加丰富,更符合我们工作 中的场景
"""
智能等待:
driver.implicitly_wait() : 括号里写上最长等待时间"""# import time
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ECdriver = webdriver.Chrome()
driver.maximize_window()
driver.get('https://www.baidu.com')
driver.find_element(By.ID,'kw').send_keys('菜鸟教程')
driver.find_element(By.ID,'su').click()
# 代码速度太快了,页面加载需要时间,让我们代码等待一会儿
# 显性等待
# 元素定位表达是元组的格式
loc = (By.PARTIAL_LINK_TEXT,' - 学的不仅是技术,更是梦想!')
# 最长等待8s 直到元素可以被点击了 才会结束等待执行后面的操作。 如果一直不可点击,timeout报错。
WebDriverWait(driver,8).until(EC.element_to_be_clickable(loc)).click()
# driver.quit()
# 既然显示等待每个元素都会用,所以封装,多次调用。
条件很多,常见的几种如下:
- presence_of_element_located(元组/列表) :给定的元素存在
- visibility_of_element_located(元组/列表) :给定的元素可见
- element_to_be_clickable(元组/列表) : 给定的元素可点击。
元素存在/可见/可用的区别: 元素存在< 可见< 可用
- 元素的存在: 能find_element就可以了。如果存在但不可见,是可以获 取元素属性的,但是不能够对元素进行操作。
- 元素的可见: 在存在的基础上,元素在页面上大小>0,即在页面上显示出 来了 肉眼可见。
- - 比如百度页面上的设置按钮,鼠标悬浮上去才会显示菜单,那么默认 情况下 这个元素是不可见的:
- - style='display:None'; 不可见,这个元素是存在但是不可见。
- - style='display:block' 元素展示出来了,可见。
- 元素的可用:在可见的基础上,能够使用其原始功能,
- 比如可点击,可输 入等 - 比如按钮可点击即可用,不可点击即不可用。输入框可输入即可用, 不可输入即不可用。下拉列表可以选可用
注意:条件的参数必须要是元组或者列表的类型的:(元素定位的方法,元素 定位表达式)
- WebDriverWait(driver, 超时时间, 轮询周期默认0.5).until(条件) 直到条件 成立
- WebDriverWait(driver, 超时时间, 轮询周期默认0.5).until_not(条件) 直到 条件不成立
- 局部生效,哪里需要等待哪里就要调用,生效只有一次。
- 如果超时时长以内没有找着元素,就会抛异常: TimeoutException,超时 异常
- 优点:可以设置更加丰富的特定条件
- 缺点:仅对指定的元素生效,代码略复杂
问题: 显示等待和隐式等待能够一起混用么?
最好不要混合一起使用,容易引起一些问题。所以,尽量不要混用。官方有说 明。在一个会话周期里不要混用。
selenium官方文档说明:
Waiting Strategies | Selenium
在项目里更多的时候是不同的等待策略的结合,比如隐式+强制等待 or 显式等 待【为主】+ 强制等待【为辅】(用的比较多),不会混用隐式+显式。
- 如果只用了智能等待,依然不生效的时候,会配合强制等待使用。后面项 目里会有这样的场景。
- 后面的框架会进行封装,显示等待在封装好关键字,后面重复调用就可以
三大切换
经典面试题: 元素报错找不到可能的原因有哪些?
1、窗口切换
当我们点击了 a 标签元素(超链接)时,会触发打开链接页面的事件,有两种 情形:
- 1、在当前窗口加载新页面内容
- 2、新建一个窗口加载新页面内容,这种情况在 a 标签有 target="_blank" 时触发。
当发生第2种情况时,我们需要切换窗口。在新的窗口里定位元素。
driver.current_window_handle(); #获取当前操作窗口的句柄
driver.window_handles(); #获取所有打开的窗口句柄
切换的步骤:
1)执行打开新窗口的操作
2)获取现在所有的窗口句柄。
- 窗口列表 : wins = driver.window_handles ,结果是个列表,最新的窗 口在列表的最后。
- 新打开的窗口追加在窗口列表末尾。
- 通过索引进行选择: wins[-1]获取最新的窗口
3)切换到最新窗口:driver.switch_to.window(窗口列表[-1])
- 切换窗口-参数windowname(窗口的名字 也就是窗口句柄)
- 需要注意,窗口的句柄并不是固定的,而是由浏览器分配的,类似于进 程号: 窗口句柄是唯一,但是并不固定 ,所以不能直接写死进行切 换。
- 需要通过获取到所有句柄后的列表 取值。
单窗口切换
"""
点击链接 打开了新窗口 要在新窗口里定位元素, 一定要切换窗口。
driver.window_handles : 拿到所有窗口句柄 放在列表里。- 句柄唯一的 但是是变化 不能直接用句柄本身去做窗口切换- 既然是放在列表里,可以用列表的索引去切换 , 最新窗口一定是最后一个:[-1]"""
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleepdriver = webdriver.Chrome()
driver.maximize_window()
driver.get('https://www.baidu.com')# 打开新的窗口之前 先获取所有的窗口句柄
wins = driver.window_handles
print(wins)
# 找到贴吧的链接
driver.find_element(By.LINK_TEXT,"贴吧").click()# 打开新的窗口之后 获取所有句柄
wins = driver.window_handles
print(wins)# 切换到最新的窗口
driver.switch_to.window(wins[-1])# 在贴吧的页面里输入文本 搜索 test == 切换成功之后,就看可以在新的页面里进行元素操作了
driver.find_element(By.NAME,"kw1").send_keys("test")
多窗口切换
"""
点击链接 打开了新窗口 要在新窗口里定位元素, 一定要切换窗口。
driver.window_handles : 拿到所有窗口句柄 放在列表里。- 句柄唯一的 但是是变化 不能直接用句柄本身去做窗口切换- 既然是放在列表里,可以用列表的索引去切换 , 最新窗口一定是最后一个:[-1]"""
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleepdriver = webdriver.Chrome()
driver.maximize_window()
driver.get('https://www.baidu.com')# 找到贴吧的链接
driver.find_element(By.LINK_TEXT,"新闻").click()
driver.find_element(By.LINK_TEXT,"图片").click()
driver.find_element(By.LINK_TEXT,"贴吧").click()# 打开新的窗口之后 获取所有句柄
wins = driver.window_handles
print(wins)# driver.switch_to.window(wins[-1]) # 切换到最新的窗口
# driver.switch_to.window(wins[-2]) # 切换到最新的窗口,用索引且会有问题。可以采用列表遍历
# for循环遍历一下列表 拿到每一个句柄 然后切换 判断一下 url title
for win in wins:if driver.current_url == "https://image.baidu.com/": # 判断当前的页面是否为想要的url地址breakelse:driver.switch_to.window(win) # 如果不是 继续切换# 切换的不是最新的一个 -- 中间的图片
driver.find_element(By.XPATH,"//span[@class='input-container_94h2R']/input").send_keys("图片")
driver.find_element(By.XPATH,"//input[@value='百度一下']").click()# # 在贴吧的页面里输入文本 搜索 test == 切换成功之后,就看可以在新的页面里进行元素操作了
# driver.find_element(By.NAME,"kw1").send_keys("test贴吧")
2、iframe切换
有些时候我们明明元素定位方式是对的,也加了等待,就是代码运行报错找不 到元素。就算加个等待也依然找不到元素,但是也没有发生窗口切换。这个时 候就检查一下是否存在子页面--iframe。
- iframe是什么?
- iframe里面放的是另外一个html页面。页面嵌套
- driver.find_element的时候,只在当前所在的html当中找元素,不可以跨 html的。
所以,如果我们要操作iframe当中html里的元素,那么必须先切换到iframe当 中的html当中去。
如何确认页面是否有iframe的步骤
- 第一个就是:你明确元素定位正确且等待到位,依然找不到元素,那么有 可能就是在iframe当中。 第二个就是:在元素定位的时候,查看上方的绝对路径链接,如果其中有2 个html,那就说明在iframe当中
iframe切换的方法:driver.switch_to.frame(有3种方式)
第一种:通过iframe的name或者id属性切换: 【QQ空间案例】
- driver.switch_to.frame("login_frame")
- 注意: 如果id是变化的,也是不可以用于定位的,要换定位方法进 行定位; 如何确认是变化的,有数字+刷新确认。| 没有id和name 属性,也需要换方法定位并切换。
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleepdriver = webdriver.Chrome() driver.maximize_window() driver.get('https://qzone.qq.com/')# 切换iframe: 1、有id 和name 直接切换 driver.switch_to.frame("login_frame")# 点击密码登录link --在iframe子页面里 需要先进行iframe切换 driver.find_element(By.ID,'switcher_plogin').click() driver.find_element(By.ID,'u').send_keys("test123") driver.find_element(By.ID,'p').send_keys("test123")sleep(2) driver.close()
第二种:识别你要操作的元素是不是在iframe当中 【126.com案例】
# 切换iframe: 使用元素定位方式定位到iframe元素,再切换。
iframe =
driver.find_element(By.XPATH,'//iframe[contains(@id,"x-URSiframe")]')
driver.switch_to.frame(iframe)
切换到iframe当中的html,再去进行元素定位和操作,就跟普通的html一样 的。
退出iframe
切到子页面里,有时候需要退回到主页面里定位,就需要退出iframe:
- driver.switch_to.default_content() --- 跳出iframe,回到默认的html当 中。如果有多层页面嵌套,一下回到最外层页面。
- driver.switch_to.parent_frame() : 回到父级页面中,只能一级一级的跳出
注意:一个主页面可能会存在多个iframe子页面,要进去另外一个 iframe,就需要先退出 再进去另外一个。
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleepdriver = webdriver.Chrome()
driver.maximize_window()
driver.get('https://126.com/')# 切换iframe- id是变化的 不能直接使用id切换 需要进行元素定位 再切换
iframe_ele = driver.find_element(By.XPATH,'//iframe[contains(@id,"x-URS-iframe")]')
driver.switch_to.frame(iframe_ele) # iframe切换# 点击密码登录link --在iframe子页面里 需要先进行iframe切换
driver.find_element(By.XPATH,'//input[@name="email"]').send_keys("test321456")
driver.find_element(By.NAME,'password').send_keys("test123")
sleep(2)# 切换回主页面 进行元素定位 - 一次性回到最原始页面
driver.switch_to.default_content()
sleep(2)
driver.find_element(By.ID,'navDlAppBtn').click() # 点击主页面的 手机app下载按钮sleep(2)
driver.close()
3、弹窗切换
【alert(警告消息框),confirm(确认消息框), prompt(提示消息对话框) 】
如果页面发生了弹窗,要点击弹窗元素,也要进行弹窗切换,不然定位不到元 素。
弹窗有三种不同类型:alert(警告消息框)、confirm(确认消息框)、 prompt(提示消息对话框) 弹
- 通过switch_to.alert()切换到弹窗
- 再使用accept、dismiss、send_keys、text方法进行操作
1)alert弹框: 本质上是js的弹框 ,需要切换后将它关掉。 ==最常见 优先掌 握
- 弹框出现后,要点击确认才会消失。
- 操作:
- accept(): 点击确定 text: 获取弹框文本
- text: 获取弹框文本
#1、 alert弹框: 本质上是js的弹框 ,需要切换后将它关掉。 ==最常见 优先掌握 from selenium import webdriver from selenium.webdriver.common.by import By from time import sleepdriver = webdriver.Chrome() driver.maximize_window() driver.get('file:///D:/BaiduNetdiskDownload/66%E6%9C%9F%E8%87%AA%E5%8A%A8%E5%8C%96/%E6%96%87%E6%A1%A3%E8%B5%84%E6%96%99/20240311_py66%E7%AC%AC%E4%BA%8C%E5%8D%81%E4%BA%94%E8%8A%82%E8%AF%BE_%E4%B8%89%E5%A4%A7%E7%AD%89%E5%BE%85%E5%92%8C%E4%B8%89%E5%A4%A7%E5%88%87%E6%8D%A2/%E5%BC%B9%E7%AA%97%E4%B8%8B%E6%8B%89%E6%A1%86demo.html') sleep(2) # 强制等待# 点击触发弹框 driver.find_element(By.ID,'alert').click()# 切换到弹框 并进行操作 print(driver.switch_to.alert.text) # 获取弹框文本 并打印 driver.switch_to.alert.accept() # 进行确认操作 关闭弹框sleep(2) driver.close()
2)confirm(确认消息框): 确认和取消两个选项,可以有如下操作:
- dismiss(): 点击取消
- accept(): 点击确定
- text: 获取弹框文本
#1、 alert弹框: 本质上是js的弹框 ,需要切换后将它关掉。 ==最常见 优先掌握 from selenium import webdriver from selenium.webdriver.common.by import By from time import sleepdriver = webdriver.Chrome() driver.maximize_window() driver.get('file:///D:/BaiduNetdiskDownload/66%E6%9C%9F%E8%87%AA%E5%8A%A8%E5%8C%96/%E6%96%87%E6%A1%A3%E8%B5%84%E6%96%99/20240311_py66%E7%AC%AC%E4%BA%8C%E5%8D%81%E4%BA%94%E8%8A%82%E8%AF%BE_%E4%B8%89%E5%A4%A7%E7%AD%89%E5%BE%85%E5%92%8C%E4%B8%89%E5%A4%A7%E5%88%87%E6%8D%A2/%E5%BC%B9%E7%AA%97%E4%B8%8B%E6%8B%89%E6%A1%86demo.html') sleep(2) # 强制等待# 点击触发弹框 driver.find_element(By.ID,'confirm').click()# 切换到弹框 并进行操作 print(driver.switch_to.alert.text) # 获取弹框文本 并打印 driver.switch_to.alert.accept() # 进行确认操作 关闭弹框 driver.find_element(By.ID,'confirm').click() driver.switch_to.alert.dismiss() # 进行取消操作 关闭弹框sleep(2) driver.close()
3)prompt(提示消息对话框),可以输入内容。 有如下四种操作:
- dismiss(): 点击取消
- accept(): 点击确定
- text: 获取框中的文本
- send_keys(): 输入文本
注意: prompt输入文本,chrome浏览器不支持,Firefox支持,chrome浏览 器的驱动bug
#1、 alert弹框: 本质上是js的弹框 ,需要切换后将它关掉。 ==最常见 优先掌握
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleepdriver = webdriver.Chrome()
driver.maximize_window()
driver.get('file:///D:/BaiduNetdiskDownload/66%E6%9C%9F%E8%87%AA%E5%8A%A8%E5%8C%96/%E6%96%87%E6%A1%A3%E8%B5%84%E6%96%99/20240311_py66%E7%AC%AC%E4%BA%8C%E5%8D%81%E4%BA%94%E8%8A%82%E8%AF%BE_%E4%B8%89%E5%A4%A7%E7%AD%89%E5%BE%85%E5%92%8C%E4%B8%89%E5%A4%A7%E5%88%87%E6%8D%A2/%E5%BC%B9%E7%AA%97%E4%B8%8B%E6%8B%89%E6%A1%86demo.html')
sleep(2) # 强制等待# 点击触发弹框
driver.find_element(By.ID,'prompt').click()# 切换到弹框 并进行操作
print(driver.switch_to.alert.text) # 获取弹框文本 并打印
driver.switch_to.alert.send_keys("输入文本")
# 注意: prompt输入文本,chrome浏览器不支持,Firefox支持,chrome浏览器的驱动bug
driver.switch_to.alert.accept() # 进行确认操作 关闭弹框
sleep(2)
driver.find_element(By.ID,'prompt').click()
driver.switch_to.alert.dismiss() # 进行取消操作 关闭弹框
sleep(2)
driver.close()
面试题:如果元素定位不到,有哪些原因??【 no such element 如何排查】
- 1、检查我们的元素定位表达式是否写错,可以F12搜索验证
- 2、检查是否是需要加等待: 智能等待+ 强制登录结合使用
- 3、检查是否元素在iframe中,如果是的话就需要切换iframe
- 4、检查元素是否在新的窗口中,如果是的话我们就需要切换窗口
- 5、是否元素不可见,先移动鼠标或者其他操作让你可见后再操作 -- 操作鼠标
- 6、是否无法直接操作,可以通过js 点击 或者键鼠操作等。 -- js点击