python之selenium的switch_to

我们在浏览器操作页面时,经常遇到打开新标签页的情况,但是在selenium的WebDriver对象中,只对当前get()打开的标签页生效,页面操作中打开的新标签页是不会更新到WebDriver对象中的,所以需要自己将WebDriver对象指定到新的标签页。

切换页面

对于页面操作的常用方法有如下:

方法 说明
current_window_handle 获取当前WebDriver对象的页面窗口句柄
window_handles 获取当前浏览器所有页面的窗口句柄。返回的是个List对象
switch_to.window(window_name) 切换到相关页面,window_name传入的是句柄

以百度首页登录和注册的页面切换为例,示例如下:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By

if __name__ == "__main__":
    driver = webdriver.Chrome()
    driver.get("https://www.baidu.com/")
    driver.implicitly_wait(20)
    driver.find_element(By.LINK_TEXT, "登录").click()
    print("----------只打开了百度首页----------")
    print(f"当前窗口句柄:{
      
      driver.current_window_handle}")
    print(f"当前所有窗口句柄:{
      
      driver.window_handles}")
    driver.find_element(By.LINK_TEXT, "立即注册").click()
    time.sleep(1)
    print("----------打开了注册页面----------")
    print(f"当前窗口句柄:{
      
      driver.current_window_handle}")
    now_pages = driver.window_handles
    print(f"当前所有窗口句柄:{
      
      now_pages}")
    driver.switch_to.window(now_pages[-1])
    print("----------切换到注册页面----------")
    print(f"当前窗口句柄:{
      
      driver.current_window_handle}")
    driver.find_element(By.ID, "TANGRAM__PSP_4__userName").send_keys("wen_xiaoba")
    time.sleep(2)
    driver.switch_to.window(now_pages[0])
    driver.find_element(By.ID, "TANGRAM__PSP_11__userName").send_keys("wen_xiaojiu")
    time.sleep(2)
    driver.quit()

结果如下:
在这里插入图片描述

frame切换

html中存在一种frame结构,可以理解为页面中嵌套了另一个页面(不是弹窗的那种),在当前页面下是定位不到frame的,也就是说,如果我们没有切换到frame中的话,我们是无法定位到frame中的元素的。
frame标签包含frameset、frame、iframe三种,我们可以根据index、id、name、webelement等方式定位frame,然后切换到frame后,再去定位frame上的元素。

方法 说明
switch_to.frame(frame_reference) 切换到对应的子frame下(只能子frame,不能孙frame)
switch_to.parent_frame() 切换到父frame下
switch_to.default_content() 切换到主页(即退出了frame,回到最初的页面)

接下来我们以菜鸟驿站中的frame例子来进行演示。

import time
from selenium import webdriver
from selenium.webdriver.common.by import By

if __name__ == "__main__":
    driver = webdriver.Chrome()
    driver.implicitly_wait(10)
    driver.get("https://www.runoob.com/try/try.php?filename=tryhtml_frame_name")

    # frame_a和frame_d都在id为iframeResult的iframe标签下,所以先要切换到iframe标签
    driver.switch_to.frame("iframeResult")  # 根据id值进行切换
    driver.switch_to.frame("frame_a")   # 切换到属性name="frame_a"的frame标签下
    # 读取 frame_a 标签的文本内容
    print(f"frame_a内的文本内容是:{
      
      driver.find_element(By.TAG_NAME, 'h3').text}")

    # 切换到当前的父frame下,即id为iframeResult的iframe标签
    driver.switch_to.parent_frame()

    # 定位frame_d所在的元素,用于切换到frame_d下
    frame_d = driver.find_element(By.XPATH, "//frameset//frame[@src='frame_d.htm']")
    # 根据frame_d这个WebElement对象,切换到frame_d这个frame下
    driver.switch_to.frame(frame_d)
    # 点击 首页
    driver.find_element(By.XPATH, "//ul[@class='mobile-nav']//a[text()='首页']").click()
    time.sleep(2)

    # 返回页面主页
    driver.switch_to.default_content()
    # 点击菜鸟教程的图标,跳转菜鸟教程首页
    driver.find_element(By.XPATH, "//div[@class='logo']//img").click()
    time.sleep(2)
    driver.quit()

执行结果如下:
在这里插入图片描述

弹框处理

弹框的表现形式有多种,比如div、frame,这2种看selenium系列的前面文章可以了解到,这里主要了解的有2种:alert弹窗、文件上传弹窗。

selenium有支持alert弹窗的方法,但是文件上传的弹窗涉及到了系统弹窗,selenium是没有支持的,网上很多方法基本上是需要第三方工具的/(ㄒoㄒ)/~~后面有好的解决办法再补充这一块

alert弹窗

alert弹窗的常用的内容如下:

方法 说明
alert = switch_to.alert 切换到alert弹窗,并将Alert对象返回给alert变量
accept() Alert对象的方法,表示确定(相当于点击了确定)
dismiss() Alert对象的方法,表示取消(相当于关闭、取消弹窗【如果有取消或关闭按钮的话】)

示例如下:

import time
from selenium import webdriver

if __name__ == "__main__":
    driver = webdriver.Chrome()
    driver.implicitly_wait(20)
    # 打开百度首页
    driver.get("https://image.baidu.com/")
    # 通过执行js语句打开alert弹框
    driver.execute_script('alert("我有一头小毛驴")')
    time.sleep(2)
    # 切换到alert弹框中
    alert = driver.switch_to.alert
    # 通过text属性获取alert弹框中的文本内容
    print(f"alert弹框的文本内容为:{
      
      alert.text}")
    # 取消弹框(相当于点击了取消按钮)
    alert.dismiss()

    time.sleep(2)
    # 通过执行js语句打开alert弹框
    driver.execute_script('alert("我是一只小小小小鸟~")')
    alert_2 = driver.switch_to.alert
    time.sleep(2)
    # 点击弹框的“确定”
    alert_2.accept()
    time.sleep(2)
    driver.quit()

执行结果如下:
在这里插入图片描述

文件上传

一般我们在文件上传的时候,都会打开系统弹窗,然后我们需要在系统弹窗中选择需要上传的文件(包括文档、图片、视频、音频等),但是selenium没有支持识别系统弹窗的方法。但是如果上传文件的元素是input标签,则可以直接对input标签send_keys(文件路径)进行文件上传,如果是非Input标签,则需要考虑第三方工具或寻找关联的input标签去调试了。

input标签

示例

如果上传按钮是个input标签,我们就直接使用send_keys(),以草料图片二维码生成器的上传为例:
在这里插入图片描述
想上传第二份时,会发现没有input标签了
在这里插入图片描述
一般而言,一个页面中,上传的元素是基本相同的,我们可以根据第一个上传前的id定位(或者扩大范围,一层层向上查input标签),从前一个截图可以看到,上传元素的input标签的id值是filedatacode,上传一个文件后,查找这个input标签是否还存在,若存在我们就继续用
在这里插入图片描述
具体代码如下:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By

if __name__ == "__main__":
    driver = webdriver.Chrome()
    driver.implicitly_wait(20)
    # 打开百度图片首页
    driver.get("https://cli.im/files")
    # 定位上传的input标签
    up_load_input = driver.find_element(By.ID, "filedatacode")
    # 上传第一个文件
    up_load_input.send_keys("E:\\图片\\demo.txt")
    time.sleep(2)
    up_load_input2 = driver.find_element(By.ID, "filedatacode")
    # 上传第二个文件
    up_load_input2.send_keys("E:\\图片\\百度翻译.png")
    time.sleep(2)
    driver.quit()

涉及到的文件如下:
在这里插入图片描述

执行结果如下:
在这里插入图片描述

小tips

有时候我们使用浏览器的定位功能,发现上传按钮不是input标签,这个时候我们可以在上传按钮的上层去找input标签,直到找到类似上传的input标签。一般而言,上传的input标签会放在被定为的按钮的子级、同级或同级的子级。
芝麻二维码解码器为例,我们使用浏览器的定位功能定位 选择二维码图片 的时候,发现是个button标签
在这里插入图片描述

我们以这个button标签为中心,向上扩展查找范围,比如扩展到 class=“decode_upload_right” 的div标签,在该div标签下查找input子标签,从xpath表达式匹配结果可以看出, 选择二维码图片 的button标签的同级标签下有一个匹配的input子标签,我们试试这个input标签的send_keys()方法是否能上传图片
在这里插入图片描述
实现如下:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By

if __name__ == "__main__":
    driver = webdriver.Chrome()
    driver.implicitly_wait(20)
    # 打开芝麻二维码解码器页面
    driver.get("https://www.hotapp.cn/jiema")
    # 定位到input标签,上传百度翻译的二维码图片
    driver.find_element(By.XPATH, "//div[@class='decode_upload_right']//input").send_keys("E:\\图片\\百度翻译.png")
    # 阻塞3秒钟,用来人眼查看效果
    time.sleep(3)
    driver.quit()

执行结果如下:
在这里插入图片描述

上传按钮非input标签

占个位置,以后有实践再安排,嘻嘻~

猜你喜欢

转载自blog.csdn.net/wenxiaoba/article/details/128890252