web自动化-三大等待,三大切换

在页面的操作过程当中,都需要适当的等待。特别是: 候【发生了页面切换的时候】。而我们接下来的操作都是在变化的内容上。 代码就要等等页面的加载,等等页面的渲染。代码是非常快的,页面加载跟不 上,就需要等待。

三大等待

面试题: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 By
    
    driver = 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 By
    
    driver = 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 EC

driver = 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 sleep

driver = 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 sleep

driver = 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地址
        break
    else:
        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 sleep
    
    driver = 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 sleep

driver = 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 sleep
      
      driver = 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 sleep
    
    driver = 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 sleep

driver = 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点击
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值