0%

Selenium4学习笔记:切换

切换的概念

Selenium 启动浏览器时,“焦点”在打开的首个窗口/标签页。但是,操作过程中,可能会需要切换“焦点”。主要包括以下几种切换场景:

  • 页面弹出新窗口/标签页,需要操作新窗口/标签页中的内容
  • 页面包括“子页面”(iframe),需要在子页面中查找
  • 页面是框架集结构,需要在框架中查找
  • 页面弹出对话框——包括:警告框(Alert)、确认框(Confirm)、提示框(Prompt)等——需要操作对话框

切换到新窗口/标签页

Selenium 不区分窗口和标签页(下文统一称“窗口”),要切换到新打开的窗口,使用如下代码:

1
driver.switch_to.window(name_or_handle)

【Java 版】

1
driver.switchTo().window(nameOrHandle);

需要注意的是,参数有两种选择,可以是窗口的名称,也可以是窗口的句柄。

窗口的名称

怎样知道窗口的名称呢?

通常,这种窗口是通过链接打开的,页面源码可能类似这样:

1
<a href="somewhere.html" target="windowName">Click here to open a new window</a>

其中 <a>target 属性值就是点击链接后打开窗口的名称。

获取窗口句柄

如果不是上述打开场景,就不能获知窗口名称,所以需要通过句柄来切换。获取句柄的代码如下:

1
2
3
4
# 当前焦点所在窗口句柄
driver.current_window_handle
# 所有窗口句柄
driver.window_handles

【Java 版】

1
2
driver.getWindowHandle();
driver.getWindowHandles();

句柄从字面上是不具有“可读性”的,所以不可能通过句柄值确定与窗口的对应关系。

通常的做法是,获取当前窗口句柄,然后从所有窗口句柄中排除当前窗口句柄,再确定要切换到的窗口句柄。

【最佳实践】

应尽量保持最多有两个窗口,以方便区分。

如果确实需要打开多个窗口,则需要每打开一个窗口就使用“排除法”获取其句柄并记录下来。

切换不会自动发生

页面操作导致在新窗口中打开新页面时,Selenium 的焦点不会自动切换,即使从浏览器行为看新窗口已获得焦点。

所以,要记得先切换焦点到新窗口,才能在新窗口进行操作,否则操作将仍在原窗口进行。对应的,使用 driver.close() 关闭新窗口时,要记得将焦点切换回原窗口,否则将试图在一个已销毁的窗口中进行操作——当然会报错啦。

新建窗口

上面所述的新窗口都是通过页面操作打开的。Selenium 4 新增了一个纯代码新建“空白”窗口的方法:

1
2
3
4
# 打开新标签页并切换到新标签页
driver.switch_to.new_window('tab')
# 打开一个新窗口并切换到新窗口
driver.switch_to.new_window('window')

【Java 版】

1
2
3
4
// 新建并转到新标签页 
WebDriver window2 = driver.switchTo().newWindow(WindowType.TAB);
// 新建并转到新窗口
WebDriver window1 = driver.switchTo().newWindow(WindowType.WINDOW);

注意,焦点会切换到新建窗口。

切换到“子文档”

涉及“子文档”的结构包括“框架集(frameset)”和“内嵌框架(iframe)”,前者已弃用很少见了,后者仍经常使用,因此将以 iframe 为例说明。

向“内”切换到“子文档”

切换到“子文档”的方法为:

1
driver.switch_to.frame(frame_reference)

注意参数可以有三种类型:

  1. 查找到的 iframe 元素
  2. iframe 元素的 id 或 name
  3. iframe 元素的索引(来自 window.frames

【Java 版】

由于 Java 是强类型语言,所以对应方法有三个重载形式。

1
2
3
driver.switchTo().frame(element); // WebElement
driver.switchTo().frame(index); // int
driver.switchTo().frame(nameOrId); // String

向“外”切换回“父文档”

切换进了“子文档”后,要想返回,使用如下方法:

1
driver.switch_to.parent_frame()

【Java 版】

1
driver.switchTo().parentFrame();

返回“主文档”

从“子文档”返回默认“主文档”的方法为:

1
driver.switch_to.default_content()

【Java 版】

1
driver.switchTo().defaultContent();

该方法使得可以不关注文档的结构,即使嵌套很深,也不需要一层层向外切换,直接一步返回顶层主文档。

处理对话框

说实话,目前网页开发大多基于各种 UI 库,弹出对话框通常都不用原生的了。操作原生对话框的方法如下:

1
2
3
4
5
6
7
8
# 点击“确认”按钮
driver.switch_to.alert.accept()
# 点击“取消”按钮
driver.switch_to.alert.dismiss()
# 获取对话框消息文本
driver.switch_to.alert.text
# 向“提示框(Prompt)”输入内容
driver.switch_to.alert.send_keys(keysToSend)

【共享的方法】

注意,Selenium 没有区别对待三种对话框:警告框(Alert)、确认框(Confirm)、提示框(Prompt)。

  • accept() 可以操作三种对话框的“确认”按钮
  • text 可以获取三种对话框的文本消息
  • dismiss() 可以操作确认框和提示框的“取消”按钮(警告框没有“取消”按钮)
  • send_keys(keysToSend) 只能向提示框输入内容(因为只有提示框有输入框)

【Java 版】

1
2
3
4
driver.switchTo().alert().accept();
driver.switchTo().alert().dismiss();
driver.switchTo().alert().getText();
driver.switchTo().alert().sendKeys(keysToSend);