在自动化测试过程中,有时后会遇到元素定位方式没有问题,但是依旧抛出无法找到元素的异常的问题,通常情况下,如果元素定位没有问题,但还是无法找到元素,则可能是由于当前焦点不在指定页面或iframe导致的,以下将对两种情况分别进行说明
1、切换窗口
比如我们现在有这样一个需求,进入百度首页后,点击新闻,然后在新闻页面的搜索框输入selenium
而使用selenium要如何实现呢,在对selenium不是很熟悉的情况下,仅仅学习了之前的内容,写出的代码就可能会抛出找不到贴吧搜索输入框元素异常,示例代码如下
from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Edge() driver.get("https://www.baidu.com/") driver.find_element(By.LINK_TEXT, '新闻').click() # 点击新闻 driver.find_element(By.ID, 'ww').send_keys('selenium') # 在新闻首页搜索框输入selenium driver.quit()
代码看起来没什么问题,打开百度首页,点击贴吧,然后在贴吧登录页面点击立即注册,元素定位也没错,但是执行就会抛出异常,无法找到贴吧的输入框元素
造成此错误的原因是因为点击新闻之后,又打开了一个新的窗口,此时打开的窗口有百度首页和新闻页,而selenium不知道我们需不需要切换窗口,所以不会自动给我们切换窗口,需要手动进行窗口的切换
而要实现窗口的切换,则需要用到获取浏览器句柄以及窗口切换的方法
1.1、获取句柄
句柄是当前浏览器窗口或选项卡的一个类似id一样的唯一标识,可以用来判断当前窗口或选项卡是否在指定的窗口,获取句柄的方法如下:
获取当前页面句柄 driver.current_window_handle 获取当前所有存在的窗口句柄,多个句柄以列表方式存储 driver.window_handles
通常的,我们只需要使用当前窗口句柄与所有窗口句柄列表进行对比,然后使用窗口切换的方法,就可以完成窗口的切换
1.2、切换窗口
要完成窗口切换,需要使用方法switch_to.window(),完成新闻页输入selenium操作完整成功的示例代码如下:
from selenium import webdriver from selenium.webdriver.common.by import By import time driver = webdriver.Edge() driver.get("https://www.baidu.com/") driver.find_element(By.LINK_TEXT, '新闻').click() # 点击新闻 handle = driver.current_window_handle # 获取当前窗口句柄 handles = driver.window_handles # 获取所有窗口句柄 for window_handle in handles: # 循环比较句柄 if window_handle != handle: # 如果窗口句柄与当前窗口句柄不一致,则切换到该窗口 driver.switch_to.window(window_handle) driver.find_element(By.ID, 'ww').send_keys('selenium') # 在新闻首页搜索框输入selenium time.sleep(2) driver.quit()
以上代码只适用于两个窗口的切换,如果同时打开更多窗口,使用上述代码只能切换到列表最后一个非当前窗口,那存在多个窗口时需要如何准确的切换到指定的窗口呢,其实只需要追加一层判断即可,示例如下:
from selenium import webdriver from selenium.webdriver.common.by import By import time driver = webdriver.Edge() driver.get("https://www.baidu.com/") driver.find_element(By.LINK_TEXT, '新闻').click() # 点击新闻 handle = driver.current_window_handle # 获取当前窗口句柄 handles = driver.window_handles # 获取所有窗口句柄 for window_handle in handles: # 循环比较句柄 if window_handle != handle: # 如果窗口句柄与当前窗口句柄不一致,则切换到该窗口 driver.switch_to.window(window_handle) if driver.title == '百度新闻——海量中文资讯平台': # 如果切换后的窗口的title与指定的一致,结束循环 break driver.find_element(By.ID, 'ww').send_keys('selenium') # 在新闻首页搜索框输入selenium time.sleep(2) driver.quit()
上述代码中添加了一层判断切换后的窗口title是否与预期一致,如果一致则跳出循环以保证多窗口切换时能够准确的切换到预期的窗口就停止切换
1.3、关闭窗口并切换回原窗口
在切换到指定窗口完成测试后,如果我们需要关闭此窗口并切换到原来的窗口,示例代码如下:
from selenium import webdriver from selenium.webdriver.common.by import By import time driver = webdriver.Edge() driver.get("https://www.baidu.com/") driver.find_element(By.LINK_TEXT, '新闻').click() # 点击新闻 handle = driver.current_window_handle # 获取当前窗口句柄 handles = driver.window_handles # 获取所有窗口句柄 for window_handle in handles: # 循环比较句柄 if window_handle != handle: # 如果窗口句柄与当前窗口句柄不一致,则切换到该窗口 driver.switch_to.window(window_handle) if driver.title == '百度新闻——海量中文资讯平台': # 如果切换后的窗口的title与指定的一致,结束循环 break driver.find_element(By.ID, 'ww').send_keys('selenium') # 在新闻首页搜索框输入selenium driver.close() # 关闭当前新闻窗口 driver.switch_to.window(handle) # 切换回原窗口,即百度首页 driver.find_element(By.ID, 'kw').send_keys('selenium') # 百度首页输入框输入selenium time.sleep(2) driver.quit()
需要注意的是,close()方法只是关闭当前所在窗口,但驱动的浏览器依旧处于等待执行状态,而quit()则会退出当前会话,无论打开了多少个窗口,均会被一次性关闭,且浏览器不再接受新的操作命令
2、切换iframe
除了打开多个窗口会导致无法找到元素之外,如果元素包含在iframe中,也会导致无法找到元素,比如现有如下元素:
<html> <iframe src="a.html" id="frame0" name="frame1"> <input id="kw" / > </iframe> </html>
此时id为kw的input标签元素处于iframe中,要定位此元素,若直接使用
driver.find_element(By.ID, ‘kw’)
也会抛出无法找到元素的异常,那么如何实现frame的切换,从而精准定位到元素呢
2.1、切换到iframe中
selenium提供了switch_to.frame()方法用于实现frame的切换,此方法接收id、name、index以及selenium的WebElement对象用来实现切换,比如上述的代码中,要切换到iframe中,则可以使用以下代码实现:
from selenium import webdriver driver = webdriver.Edge() driver.switch_to.frame('frame0') # 通过id切换iframe # driver.switch_to.frame('frame1') # 通过name切换iframe # driver.switch_to.frame(0) # 通过index切换iframe,0代表第一个 # driver.switch_to.frame(driver.find_element_by_tag_name("iframe")) # 通过WebElement对象切换iframe
一般情况下,通过id或name即可解决大部分iframe切换的问题,如果没有这两个属性,再考虑使用index以及WebElement对象来实现
2.2、从frame中切换到主界面
在测试过程中,我们不仅会从主界面切换到iframe中,当操作完frame中的元素后,经常需要重新切换到主界面进行其他操作,切换回主页面使用方法如下:
driver.switch_to.default_content()
2.3、嵌套多层iframe的切换
有时候我们会遇到嵌套多层frame的情况,如下所示
<html> <iframe src="a.html" id="frame1"> <iframe src="b.html" id="frame2" > <input id="kw" / > </iframe> </iframe> </html>
多层嵌套的情况下,如果要从主界面切换到第二层iframe,则需要一层一层的切换进去,即先切换到frame1,再切换到frame2,而不是直接切换进入frame2
driver.switch_to.frame(“frame1”)
driver.switch_to.frame(“frame2”)
selenium还提供了一个切换到父frame的方法,比如我们切换到frame2之后,要想切换到frame1操作,则不需要先切回主界面再切换到frame,而是使用如下方法:
driver.switch_to.parent_frame()
需要注意的是,如果当前已经是主页面,则使用此方法无效
灵活使用以上方法,则可轻松应对iframe的切换与窗口切换的问题,从此告别定位不到元素的苦恼
————————————————
版权声明:本文为CSDN博主「Tester_谜城」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_18298049/article/details/117303257