这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

WebDriver

WebDriver以原生的方式驱动浏览器, 在此了解更多内容.

WebDriver 以本地化方式驱动浏览器,就像用户在本地或使用 Selenium 服务器的远程机器上所做的那样,这标志着浏览器自动化的飞跃。

Selenium WebDriver 指的是语言绑定和各个浏览器控制代码的实现。 这通常被称为 WebDriver

Selenium WebDriver 是 W3C 推荐标准

  • WebDriver 被设计成一个简单和简洁的编程接口。

  • WebDriver 是一个简洁的面向对象 API。

  • 它能有效地驱动浏览器。

1 - 入门指南

如果你是Selenium的新手, 我们有一些资源帮助你快速入门.

Selenium 通过使用 WebDriver 支持市场上所有主流浏览器的自动化。 Webdriver 是一个 API 和协议,它定义了一个语言中立的接口,用于控制 web 浏览器的行为。 每个浏览器都有一个特定的 WebDriver 实现,称为驱动程序。 驱动程序是负责委派给浏览器的组件,并处理与 Selenium 和浏览器之间的通信。

这种分离是有意识地努力让浏览器供应商为其浏览器的实现负责的一部分。 Selenium 在可能的情况下使用这些第三方驱动程序, 但是在这些驱动程序不存在的情况下,它也提供了由项目自己维护的驱动程序。

Selenium 框架通过一个面向用户的界面将所有这些部分连接在一起, 该界面允许透明地使用不同的浏览器后端, 从而实现跨浏览器和跨平台自动化。

Selenium 设置与其他商业工具的设置完全不同。 要在自动化项目中使用 Selenium,您需要为您选择的语言安装语言绑定库。 此外,对于要自动运行并运行测试的浏览器,您将需要 WebDriver 二进制文件。

安装Selenium可分为三个步骤:

  1. 安装Selenium类库 为你最喜爱的编程语言
  2. 配置浏览器驱动 用以驱动你的浏览器 (例如GeckoDriver用于Firefox)
  3. (可选) 设置和配置 Selenium Grid 如果你想要扩展你的测试

如果您希望从低代码/录制和播放工具开始, 请检查 Selenium IDE

完成安装后,可以在你的文档 starting page 中运行. 然后前往 WebDriver 部分 了解更多关于 使用Selenium实现浏览器自动化的信息.

1.1 - 安装浏览器驱动

配置自动化的浏览器.

首先,您需要为自动化项目安装 Selenium 绑定库。 库的安装过程取决于您选择使用的语言。

可以使用 Maven 安装 Java 的 Selenium 库。 在项目 pom.xml 中添加 selenium-java 依赖项:

<dependency>
  <groupId>org.seleniumhq.selenium</groupId>
  <artifactId>selenium-java</artifactId>
  <version>4.X</version>
</dependency>

selenium-java 依赖项支持在所有 Selenium 支持的浏览器中运行自动化项目。 如果只想在特定的浏览器中运行测试,可以在 pom.xml 文件中添加该浏览器的依赖项。 例如,您应该在 pom.xml 文件中添加以下依赖项,以便于只在 Firefox 中运行测试:

<dependency>
  <groupId>org.seleniumhq.selenium</groupId>
  <artifactId>selenium-firefox-driver</artifactId>
  <version>4.X</version>
</dependency>

同样,如果您只想在 Chrome 上运行测试,您应该添加以下依赖项:

<dependency>
  <groupId>org.seleniumhq.selenium</groupId>
  <artifactId>selenium-chrome-driver</artifactId>
  <version>4.X</version>
</dependency>

可以使用 pip 安装 Python 的 Selenium 库:

pip install selenium

或者,您也可以下载 PyPI source archive (selenium-x.x.x.tar.gz) 并使用 setup.py 进行安装:

python setup.py install

可以使用 NuGet 安装 C# 的 Selenium 库:

# Using package manager
Install-Package Selenium.WebDriver
# or using .Net CLI
dotnet add package Selenium.WebDriver

支持的 .NET 版本

确保使用与.NET SDK版本兼容的相关Selenium包. 检查依赖的部分用以找出支持的 .NET 版本. 在本次升级时, .NET 5.0 (Visual Studio 2019) 是已知的被支持的版本, 并且 .NET 6.0 并未支持. 您可以下载 MSBuild Tools 2019 于此 以安装所需的组件和依赖项, 例如 .NET SDK 和 NuGet 包管理器.

使用 Visual Studio Code (vscode) 以及 C#

这是一个快速指南, 可帮助您开始使用 vscode 和 C#, 但可能需要进行更多调研. 按照上一节安装兼容的 .NET SDK. 还要安装适用于 C# 和 NuGet 的 vscode 扩展 (Ctrl-Shift-X). 参考 此处指令 创建并且使用C#运行 “Hello World” 的控制台项目. 您也可以使用命令行 dotnet new NUnit创建一个 NUnit 初创项目. 确保文件 %appdata%\NuGet\nuget.config 已正确配置, 因为某些开发人员报告说, 由于某些问题, 该文件将为空. 如果 nuget.config 为空, 或者未正确配置, 则Selenium项目的.NET构建将失败. 将以下部分添加到文件 nuget.config (如果为空) :

<configuration>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="nuget.org" value="https://www.nuget.org/api/v2/" />   
  </packageSources>
...

有关 nuget.config 的更多信息点此. 你也可以自定义 nuget.config 以满足所需.

现在, 返回 vscode, 按 Ctrl-Shift-P, 然后键入"NuGet Add Package", 然后输入所需的 Selenium 包, 如"Selenium.WebDriver".

按 Enter 并选择版本.

现在, 您可以通过vscode与文档中 C# 相关示例结合使用.

可以使用 gem 安装 Ruby 的 Selenium 库:

gem install selenium-webdriver

可以使用 npm 安装 JavaScript 的 Selenium 库

npm install selenium-webdriver
由于缺少Kotlin的原生语言的绑定, 您不得不借助Java的生态环境, 例如Maven Java

下一步

安装浏览器驱动

1.2 - 安装浏览器驱动

设置您的浏览器用于自动化.

通过WebDriver, Selenium支持市场上所有主要浏览器, 如Chrome、Firefox、Internet Explorer、Edge、Opera和Safari. WebDriver尽量使用浏览器内置的自动化支持 来驱动浏览器.

由于除Internet Explorer之外的所有驱动程序实现 都是由浏览器供应商自己提供的, 因此标准Selenium发行版中不包括这些驱动程序. 本节介绍了使用不同浏览器的基本要求.

在我们的驱动程序配置 文档中 阅读有关启动驱动程序的更多高级选项.

快速参考

浏览器支持的操作系统维护者下载问题追溯
Chromium/ChromeWindows/macOS/LinuxGoogle下载Issues
FirefoxWindows/macOS/LinuxMozilla下载Issues
EdgeWindows/macOSMicrosoft下载Issues
Internet ExplorerWindowsSelenium Project下载Issues
SafarimacOS High Sierra and newerApple内置Issues

注意: Opera驱动程序不支持w3c语法, 因此我们建议使用chromedriver来处理Opera. 请参见打开Opera浏览器的代码示例

使用驱动的三种方式

1. 驱动管理软件

大多数机器会自动更新浏览器, 但驱动程序不会. 为了确保为浏览器提供正确的驱动程序, 这里有许多第三方库可为您提供帮助.

  1. 导入 WebDriverManager
import io.github.bonigarcia.wdm.WebDriverManager;
  1. 调用 setup() 会自动将正确的浏览器驱动程序 放在代码可以看到的位置:
WebDriverManager.chromedriver().setup();
  1. 只需像平常一样初始化驱动程序:
ChromeDriver driver = new ChromeDriver();
  1. 导入 WebDriver Manager for Python
from webdriver_manager.chrome import ChromeDriverManager
  1. 使用 install() 获取管理器使用的位置, 并将其传递到服务类中
service = Service(executable_path=ChromeDriverManager().install())
  1. 使用 Service 实例并初始化驱动程序:
driver = webdriver.Chrome(service=service)
  1. 导入 WebDriver Manager Package
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;
  1. 使用 SetUpDriver() 时需要一个配置类:
new DriverManager().SetUpDriver(new ChromeConfig());
  1. 像往常一样初始化驱动程序:
var driver = new ChromeDriver()
  1. 增加 webdrivers gem 到 Gemfile:
gem 'webdrivers', '~> 5.0'
  1. 在程序中Require webdrivers:
require 'webdrivers'
  1. 像往常一样初始化驱动程序:
driver = Selenium::WebDriver.for :chrome
There is not a recommended driver manager for JavaScript at this time
  1. 导入 WebDriver Manager
import io.github.bonigarcia.wdm.WebDriverManager;
  1. 在初始化驱动程序之前调用setup方法:
fun chrome(): WebDriver {
    WebDriverManager.chromedriver().setup()
    return ChromeDriver()
}

2. PATH 环境变量

此选项首先需要手动下载驱动程序 (有关链接, 请参阅快速参考 部分).

这是一个灵活的选项, 可以在不更新代码的情况下更改驱动程序的位置, 并且可以在多台机器上工作, 而不需要每台机器将驱动程序放在同一位置.

您可以将驱动程序放置在路径中已列出的目录中, 也可以将其放置在目录中并将其添加到PATH.

  • 要查看PATH上已有哪些目录, 请打开命令提示符/终端并键入:

要查看PATH上已经有哪些目录, 请打开Terminal并执行

echo $PATH

如果驱动程序的位置不在列出的目录中, 可以将新目录添加到PATH:

echo 'export PATH=$PATH:/path/to/driver' >> ~/.bash_profile
source ~/.bash_profile

您可以通过启动驱动程序来测试其是否被正确添加:

chromedriver

要查看PATH上已经有哪些目录, 请打开Terminal并执行:

echo $PATH

如果驱动程序的位置不在列出的目录中, 可以将新目录添加到PATH:

echo 'export PATH=$PATH:/path/to/driver' >> ~/.zshenv
source ~/.zshenv

您可以通过启动驱动程序来测试其是否被正确添加:

chromedriver

要查看PATH上已经有哪些目录, 请打开命令提示符并执行:

echo %PATH%

如果驱动程序的位置不在列出的目录中, 可以将新目录添加到PATH:

setx PATH "%PATH%;C:\WebDriver\bin"

您可以通过启动驱动程序来测试其是否被正确添加:

chromedriver.exe

如果PATH配置正确, 您将看到一些与驱动程序启动相关的输出:

Starting ChromeDriver 95.0.4638.54 (d31a821ec901f68d0d34ccdbaea45b4c86ce543e-refs/branch-heads/4638@{#871}) on port 9515
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully.

想要重新控制命令提示符可以按下 Ctrl+C

3. 硬编码位置

与上面的选项2类似, 您需要手动下载驱动程序(有关链接, 请参阅快速参考 部分). 在代码中指定位置本身的优点是 不需要指出系统上的环境变量, 但缺点是使代码的灵活性大大降低.

System.setProperty("webdriver.chrome.driver","/path/to/chromedriver");
ChromeDriver driver = new ChromeDriver();
from selenium import webdriver
from selenium.webdriver.chrome.service import Service

service = Service(executable_path="/path/to/chromedriver")
driver = webdriver.Chrome(service=service)
var driver = new ChromeDriver(@"C:\WebDriver\bin");
service = Selenium::WebDriver::Service.chrome(path: '/path/to/chromedriver')
driver = Selenium::WebDriver.for :chrome, service: service
const {Builder} = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');

const service = new chrome.ServiceBuilder('/path/to/chromedriver');
const driver = new Builder().forBrowser('chrome').setChromeService(service).build();
import org.openqa.selenium.chrome.ChromeDriver

fun main(args: Array<String>) {
    System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver")
    val driver = ChromeDriver()
}

高级配置

有关如何更改驱动程序行为的更多信息, 请参见配置驱动程序参数 页面

下一步

打开和关闭浏览器

1.3 - 使用Selenium打开和关闭浏览器

使用每种浏览器启动和停止会话的代码示例.

当你已经完成 安装Selenium类库, 以及 浏览器所需的驱动, 您可以使用浏览器启动和停止会话.

通常, 浏览器都是根据特定的选项启动, 这些选项描述浏览器必须支持哪些功能, 以及浏览器在会话期间应如何运行. 有些功能由所有浏览器共享, 有些功能特定于所使用的浏览器. 此页面将显示使用默认功能启动浏览器的示例.

在学习如何开启一个会话后, 请查看下一段内容关于如何 编写第一个Selenium脚本的会话

Chrome

默认情况下, Selenium 4与Chrome v75及更高版本兼容. 请注意, Chrome浏览器和chromedriver的版本必须与主版本匹配.

除了共享功能外, 还可以使用特定的Chrome功能.

  ChromeOptions options = new ChromeOptions();
  driver = new ChromeDriver(options);
  
  driver.quit();
  
  options = ChromeOptions()
  driver = webdriver.Chrome(options=options)

  driver.quit()
  
  var options = new ChromeOptions();
  var driver = new ChromeDriver(options);

  driver.Quit();
  
  options = Selenium::WebDriver::Options.chrome
  driver = Selenium::WebDriver.for :chrome, options: options

  driver.quit
  
const {Builder} = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');

(async function openChromeTest() {
  try {
    let options = new chrome.Options();
    let driver = await new Builder()
                .setChromeOptions(options)
                .forBrowser('chrome')
                .build();
    await driver.get('https://www.google.com');
    await driver.quit();
  } catch (error) {
    console.log(error)
  }
})();
  val options = ChromeOptions()
  val driver = ChromeDriver(options)

  driver.quit()
  

Edge

微软Edge是用Chromium实现的, 是最早支持的v79版本. 与Chrome类似, edgedriver的主要版本号必须与Edge浏览器的主要版本匹配.

  EdgeOptions options = new EdgeOptions();
  driver = new EdgeDriver(options);

  driver.quit();
  
  options = EdgeOptions()
  driver = webdriver.Edge(options=options)

  driver.quit()
  
  var options = new EdgeOptions();
  var driver = new EdgeDriver(options);
  
  driver.Quit();
  
  options = Selenium::WebDriver::Options.edge
  driver = Selenium::WebDriver.for :edge, options: options

  driver.quit
  
const {Builder} = require('selenium-webdriver');
const edge = require('selenium-webdriver/edge');

(async function openEdgeTest() {
  try {
    let options = new edge.Options();
    let driver = await new Builder()
                .setChromeOptions(options)
                .forBrowser('edge')
                .build();
    await driver.get('https://www.google.com');
    await driver.quit();
  } catch (error) {
    console.log(error)
  }
})();
  val options = EdgeOptions()
  val driver = EdgeDriver(options)

  driver.quit()
  

Firefox

Selenium 4需要Firefox 78或更高版本. 建议始终使用geckodriver的最新版本.

  FirefoxOptions options = new FirefoxOptions();
  driver = new FirefoxDriver(options);

  driver.quit();
  
  options = FirefoxOptions()
  driver = webdriver.Firefox(options=options)

  driver.quit()
  
  var options = new FirefoxOptions();
  var driver = new FirefoxDriver(options);
  
  driver.Quit();
  
  options = Selenium::WebDriver::Options.firefox
  driver = Selenium::WebDriver.for :firefox, options: options

  driver.quit
  
const {Builder} = require('selenium-webdriver');
const firefox = require('selenium-webdriver/firefox');

(async function openFirefoxTest() {
  try {
    let options = new firefox.Options();
    let driver = await new Builder()
                .setChromeOptions(options)
                .forBrowser('firefox')
                .build();
    await driver.get('https://www.google.com');
    await driver.quit();
  } catch (error) {
    console.log(error)
  }
})();
  val options = FirefoxOptions()
  val driver = FirefoxDriver(options)

  driver.quit()
  

Internet Explorer

IE驱动程序是Selenium项目直接维护的唯一驱动程序. 虽然32位和64位版本的Internet Explorer都有可执行文件, 但64位驱动程序存在一些限制. 因此, 建议使用32位驱动程序.

Legacy

Selenium项目旨在支持微软认为最新的版本. 旧版本可能会工作, 但不受支持. 请注意, Internet Explorer 11将于2022年6月15日终止对包括Windows 10在内的某些操作系统的支持.

需要注意的是, 由于Internet Explorer首选项是针对登录用户的帐户保存的, 因此需要进行一些额外的设置.

有关使用Internet Explorer的更多信息, 请访问Selenium wiki

  InternetExplorerOptions options = new InternetExplorerOptions();
  driver = new InternetExplorerDriver(options);

  driver.quit();
  
  options = IEOptions()
  driver = webdriver.Ie(options=options)

  driver.quit()
  
  var options = new InternetExplorerOptions();
  var driver = new InternetExplorerDriver(options);
  
  driver.Quit();
  
  options = Selenium::WebDriver::Options.ie
  driver = Selenium::WebDriver.for :ie, options: options

  driver.quit
  
  const { Builder } = require("selenium-webdriver");
  const ie = require('selenium-webdriver/ie');

  let options = new ie.Options();
  let driver = await new Builder()
    .forBrowser('internetExplorer')
    .setIeOptions(options)
    .build();

  await driver.quit();
 
  val options = InternetExplorerOptions()
  val driver = InternetExplorerDriver(options)

  driver.quit()
  

兼容模式

可以使用IE驱动程序在IE兼容模式下使用微软Edge.

  InternetExplorerOptions options = new InternetExplorerOptions();
  options.attachToEdgeChrome();
  options.withEdgeExecutablePath("/path/to/edge/browser");
  
  driver = new InternetExplorerDriver(options);
  
  driver.quit();
  
  options = IEOptions()
  options.attach_to_edge_chrome = True
  options.edge_executable_path = "/path/to/edge/browser"
  driver = webdriver.Ie(options=options)

  driver.quit()
  
  var options = new InternetExplorerOptions
  {
    AttachToEdgeChrome = true,
    EdgeExecutablePath = "/path/to/edge/browser"
  };
  var driver = new InternetExplorerDriver(options);
  
  driver.Quit();
  
  options = Selenium::WebDriver::Options.ie
  options.attach_to_edge_chrome = true
  options.edge_executable_path = "/path/to/edge/browser"
  driver = Selenium::WebDriver.for :ie, options: options

  driver.quit
  
  let options = new ie.Options();
  options.setEdgeChromium(true);
  options.setEdgePath("/path/to/edge/browser);

  let driver = await new Builder()
    .forBrowser('internet explorer')
    .setIEOptions(options)
    .build();

  await driver.quit();
  
  val options = InternetExplorerOptions()
  options.attachToEdgeChrome()
  options.withEdgeExecutablePath("/path/to/edge/browser")
  val driver = InternetExplorerDriver(options)

  driver.quit()
  

Opera

由于opera驱动程序未设置w3c为默认语法, 但基于Chrome, 因此建议使用chromedriver驱动opera浏览器. 与所有Chromium实现一样, 确保浏览器版本与驱动程序版本匹配.

  //    Set webdriver.chrome.driver with Opera Driver
  System.setProperty("webdriver.chrome.driver", "OPERA_DRIVER_PATH");
  //    Create ChromeOptions Instance
  ChromeOptions chromeOptions = new ChromeOptions();
  //    Set W3C Dialect
  chromeOptions.setExperimentalOption("w3c", true);
  //    Create ChromeDriver Instance
  WebDriver driver = new ChromeDriver(chromeOptions);
  //    Open Target Website
  driver.get("https://www.selenium.dev");
  //    Quit
  driver.quit();
  
  options = ChromeOptions()
  options.binary_location = "path/to/opera/browser"
  driver = webdriver.Chrome(options=options)

  driver.quit()
  
  var options = new ChromeOptions
  {
    BinaryLocation = "/path/to/opera/browser"
  };
  var driver = new ChromeDriver(options);
  
  driver.Quit();
  
  options = Selenium::WebDriver::Options.chrome
  options.binary = '/path/to/opera/browser'
  driver = Selenium::WebDriver.for :chrome, options: options

  driver.quit
  
  const { Builder } = require("selenium-webdriver");
  const chrome = require('selenium-webdriver/chrome');

  let options = new chrome.Options();
  options.setChromeBinaryPath("/path/to/opera/browser");

  let driver = await new Builder()
    .forBrowser('chrome')
    .setChromeOptions(options)
    .build();

  await driver.quit();
  
  val options = ChromeOptions()
  options.setBinary("/path/to/opera/browser")
  val driver = ChromeDriver(options)
  
  driver.quit()
  

Safari

Desktop

与Chromium和Firefox驱动程序不同, safaridriver是随操作系统一起安装的. 要在Safari上启用自动化, 请从命令行运行以下命令:

safaridriver --enable
  SafariOptions options = new SafariOptions();
  driver = new SafariDriver(options);
  
  driver.quit();
  driver = webdriver.Safari()

  driver.quit()
  
  var options = new SafariOptions();
  var driver = new SafariDriver(options);

  driver.Quit();
  
  options = Selenium::WebDriver::Options.safari
  driver = Selenium::WebDriver.for :safari, options: options

  driver.quit
  
  const { Builder } = require("selenium-webdriver");
  const safari = require('selenium-webdriver/safari');

  let options = new safari.Options();
  let driver = await new Builder()
    .forBrowser('safari')
    .setSafariOptions(options)
    .build();

  await driver.quit();
  
  val options = SafariOptions()
  val driver = SafariDriver(options)

  driver.quit()
  

移动端

那些希望在iOS上实现Safari自动化的人 应该看看Appium项目.

下一步

创建你的第一个Selenium脚本

1.4 - 编写第一个Selenium脚本

逐步构建一个Selenium脚本的说明

当你完成 Selenium安装 and 驱动安装 后, 便可以开始书写Selenium脚本了.

八个基本组成部分

Selenium所做的一切, 就是发送给浏览器命令, 用以执行某些操作或为信息发送请求. 您将使用Selenium执行的大部分操作, 都是以下基本命令的组合:

1. 使用驱动实例开启会话

有关启动会话的更多详细信息, 请阅读我们关于打开和关闭浏览器的文档

        driver = new ChromeDriver();
    driver = webdriver.Chrome()
            var driver = new ChromeDriver();
    driver = Selenium::WebDriver.for :chrome
    let driver = await new Builder().forBrowser('chrome').build();
        driver = ChromeDriver()

2. 在浏览器上执行操作

在本例中, 我们 导航 到一个网页.

        driver.get("https://google.com");
    driver.get("https://google.com")
            driver.Navigate().GoToUrl("https://google.com");
    driver.get('https://google.com')
    await driver.get('https://www.google.com');
        driver.get("https://google.com")

3. 请求 浏览器信息

您可以请求一系列关于浏览器的信息 , 包括窗口句柄、浏览器尺寸/位置、cookie、警报等.

        String title = driver.getTitle();
    title = driver.title
            var title = driver.Title;
    title = driver.title
    await driver.getTitle();
        title = driver.title

4. 建立等待策略

将代码与浏览器的当前状态同步 是Selenium面临的最大挑战之一, 做好它是一个高级主题.

基本上, 您希望在尝试定位元素之前, 确保该元素位于页面上, 并且在尝试与该元素交互之前, 该元素处于可交互状态.

隐式等待很少是最好的解决方案, 但在这里最容易演示, 所以我们将使用它作为占位符.

阅读更多关于等待策略 的信息.

        driver.manage().timeouts().implicitlyWait(Duration.ofMillis(500));
    driver.implicitly_wait(0.5)
            driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(500);
    driver.manage.timeouts.implicit_wait = 500
    await driver.manage().setTimeouts({implicit: 1000})
        driver.manage().timeouts().implicitlyWait(Duration.ofMillis(500))

5. 发送命令 查找元素

大多数Selenium会话中的主要命令都与元素相关, 如果不先找到元素, 就无法与之交互.

        WebElement searchBox = driver.findElement(By.name("q"));
        WebElement searchButton = driver.findElement(By.name("btnK"));
    search_box = driver.find_element(by=By.NAME, value="q")
    search_button = driver.find_element(by=By.NAME, value="btnK")
            var searchBox = driver.FindElement(By.Name("q"));
            var searchButton = driver.FindElement(By.Name("btnK"));
    search_box = driver.find_element(name: 'q')
    search_button = driver.find_element(name: 'btnK')
    let searchBox = await driver.findElement(By.name('q'));
    let searchButton = await driver.findElement(By.name('btnK'));
        var searchBox = driver.findElement(By.name("q"))
        val searchButton = driver.findElement(By.name("btnK"))

6. 操作元素

对于一个元素, 只有少数几个操作可以执行, 但您将经常使用它们.

        searchBox.sendKeys("Selenium");
        searchButton.click();
    search_box.send_keys("Selenium")
    search_button.click()
            searchBox.SendKeys("Selenium");
            searchButton.Click();
    search_box.send_keys('Selenium')
    search_button.click
    await searchBox.sendKeys('Selenium');
    await searchButton.click();
        searchBox.sendKeys("Selenium")
        searchButton.click()

7. 获取元素信息

元素存储了很多被请求的信息. 请注意, 我们需要重新定位搜索框, 因为自从我们第一次找到它以来, DOM已经发生了变化.

        String value = searchBox.getAttribute("value");
    value = search_box.get_attribute("value")
            var value = searchBox.GetAttribute("value");
    value = search_box.attribute('value')
    let value = await searchBox.getAttribute("value");
        val value = searchBox.getAttribute("value")

8. 结束会话

这将结束驱动程序进程, 默认情况下, 该进程也会关闭浏览器. 无法向此驱动程序实例发送更多命令.

        driver.quit();
    driver.quit()
            driver.Quit();
    await driver.quit();
        driver.quit()

组合所有事情

让我们将这8个部分组合成一个完整的脚本, 包括需要使用的库:

按照选项卡底部的链接查看代码示例, 因为它将使用测试运行程序而不是独立文件执行.

package dev.selenium.getting_started;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

import java.time.Duration;

public class FirstScriptTest {
    public WebDriver driver;

    @Test
    public void eightComponents() {
        driver = new ChromeDriver();

        driver.get("https://google.com");

        String title = driver.getTitle();
        Assertions.assertEquals("Google", title);

        driver.manage().timeouts().implicitlyWait(Duration.ofMillis(500));

        WebElement searchBox = driver.findElement(By.name("q"));
        WebElement searchButton = driver.findElement(By.name("btnK"));

        searchBox.sendKeys("Selenium");
        searchButton.click();

        searchBox = driver.findElement(By.name("q"));
        String value = searchBox.getAttribute("value");
        Assertions.assertEquals("Selenium", value);

        driver.quit();
    }
}
from selenium import webdriver
from selenium.webdriver.common.by import By


def test_eight_components():
    driver = webdriver.Chrome()

    driver.get("https://google.com")

    title = driver.title
    assert title == "Google"

    driver.implicitly_wait(0.5)

    search_box = driver.find_element(by=By.NAME, value="q")
    search_button = driver.find_element(by=By.NAME, value="btnK")

    search_box.send_keys("Selenium")
    search_button.click()

    search_box = driver.find_element(by=By.NAME, value="q")
    value = search_box.get_attribute("value")
    assert value == "Selenium"

    driver.quit()
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace SeleniumDocs.GettingStarted
{
    [TestClass]
    public class FirstScriptTest
    {

        [TestMethod]
        public void ChromeSession()
        {
            var driver = new ChromeDriver();

            driver.Navigate().GoToUrl("https://google.com");

            var title = driver.Title;
            Assert.AreEqual("Google", title);

            driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(500);

            var searchBox = driver.FindElement(By.Name("q"));
            var searchButton = driver.FindElement(By.Name("btnK"));
            
            searchBox.SendKeys("Selenium");
            searchButton.Click();
            
            searchBox = driver.FindElement(By.Name("q"));
            var value = searchBox.GetAttribute("value");
            Assert.AreEqual("Selenium", value);

            driver.Quit();
        }
    }
}
# frozen_string_literal: true

RSpec.describe 'First Script' do
  it 'uses eight components' do
    driver = Selenium::WebDriver.for :chrome

    driver.get('https://google.com')

    title = driver.title
    expect(title).to eq('Google')

    driver.manage.timeouts.implicit_wait = 500

    search_box = driver.find_element(name: 'q')
    search_button = driver.find_element(name: 'btnK')

    search_box.send_keys('Selenium')
    search_button.click

    search_box = driver.find_element(name: 'q')
    value = search_box.attribute('value')
    expect(value).to eq('Selenium')

    driver.quit
  end
end
const {Builder, By} = require('selenium-webdriver');
const assert = require('assert');

(async function firstScript() {
  try {
    let driver = await new Builder().forBrowser('chrome').build();

    await driver.get('https://www.google.com');

    await driver.getTitle();

    await driver.manage().setTimeouts({implicit: 1000})

    let searchBox = await driver.findElement(By.name('q'));
    let searchButton = await driver.findElement(By.name('btnK'));

    await searchBox.sendKeys('Selenium');
    await searchButton.click();

    let value = await searchBox.getAttribute("value");
    assert.deepStrictEqual(value, "Selenium")

    await driver.quit();
  } catch (error) {
    console.log(error)
  }
})();
package dev.selenium.getting_started

import io.github.bonigarcia.wdm.WebDriverManager
import org.junit.jupiter.api.*
import org.junit.jupiter.api.Assertions.assertEquals
import org.openqa.selenium.By
import org.openqa.selenium.WebDriver
import org.openqa.selenium.chrome.ChromeDriver
import java.time.Duration

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class FirstScriptTest {
    private lateinit var driver: WebDriver

    @Test
    fun eightComponents() {
        driver = ChromeDriver()

        driver.get("https://google.com")

        title = driver.title
        assertEquals("Google", title)

        driver.manage().timeouts().implicitlyWait(Duration.ofMillis(500))

        var searchBox = driver.findElement(By.name("q"))
        val searchButton = driver.findElement(By.name("btnK"))

        searchBox.sendKeys("Selenium")
        searchButton.click()

        searchBox = driver.findElement(By.name("q"))
        val value = searchBox.getAttribute("value")
        assertEquals("Selenium", value)

        driver.quit()
    }
}

接下来的步骤

利用你所学的知识, 构建你的Selenium代码.

当您发现需要更多功能时, 请阅读我们的WebDriver文档的其余部分.

1.5 - 升级到Selenium 4

对Selenium 4感兴趣? 查看本指南, 它将帮助您升级到最新版本!

如果您使用的是官方支持的语言 (Ruby、JavaScript、C#、Python和Java), 那么升级到Selenium 4应该是一个轻松的过程. 在某些情况下可能会出现一些问题, 本指南将帮助您解决这些问题. 我们将完成升级项目依赖项的步骤, 并了解版本升级带来的主要反对意见和更改.

请按照以下步骤升级到Selenium 4:

  • 准备我们的测试代码
  • 升级依赖
  • 潜在错误和弃用消息

注意:在开发Selenium 3.x版本的同时, 实现了对W3C WebDriver标准的支持. 此新协议和遗留JSON Wire协议均受支持. 在3.11版前后, Selenium代码与W3C 1级规范兼容. 最新版本的Selenium 3中的W3C兼容代码将在Selenium 4中正常工作.

准备测试代码

Selenium 4 移除了对遗留协议的支持, 并在底层实现上默认使用 W3C WebDriver 标准.
对于大多数情况, 这种实现不会影响终端用户.
主要的例外是 CapabilitiesActions 类.

Capabilities

如果测试capabilities的结构不符合 W3C标准, 可能会导致会话无法正常开启.
以下是 W3C WebDriver 标准capabilities列表:

  • browserName
  • browserVersion (替代 version)
  • platformName (替代 platform)
  • acceptInsecureCerts
  • pageLoadStrategy
  • proxy
  • timeouts
  • unhandledPromptBehavior

可以在以下位置找到标准capabilities的最新列表 W3C WebDriver.

上面列表中未包含的任何capability, 都需要包含供应商前缀. 这适用于浏览器特定capability 以及云供应商特定capability. 例如, 如果您的云供应商为您的测试 使用 buildname capability, 您需要将它们包装在一个 cloud: options 块中 (请与您的云供应商联系以获取适当的前缀).

Before

DesiredCapabilities caps = DesiredCapabilities.firefox();
caps.setCapability("platform", "Windows 10");
caps.setCapability("version", "92");
caps.setCapability("build", myTestBuild);
caps.setCapability("name", myTestName);
WebDriver driver = new RemoteWebDriver(new URL(cloudUrl), caps);
caps = {};
caps['browserName'] = 'Firefox';
caps['platform'] = 'Windows 10';
caps['version'] = '92';
caps['build'] = myTestBuild;
caps['name'] = myTestName;
DesiredCapabilities caps = new DesiredCapabilities();
caps.SetCapability("browserName", "firefox");
caps.SetCapability("platform", "Windows 10");
caps.SetCapability("version", "92");
caps.SetCapability("build", myTestBuild);
caps.SetCapability("name", myTestName);
var driver = new RemoteWebDriver(new Uri(CloudURL), caps);
caps = Selenium: : WebDriver: : Remote: : Capabilities.firefox
caps[: platform] = 'Windows 10'
caps[: version] = '92'
caps[: build] = my_test_build
caps[: name] = my_test_name
driver = Selenium: : WebDriver.for : remote, url:  cloud_url, desired_capabilities:  caps
caps = {}
caps['browserName'] = 'firefox'
caps['platform'] = 'Windows 10'
caps['version'] = '92'
caps['build'] = my_test_build
caps['name'] = my_test_name
driver = webdriver.Remote(cloud_url, desired_capabilities=caps)

After

FirefoxOptions browserOptions = new FirefoxOptions();
browserOptions.setPlatformName("Windows 10");
browserOptions.setBrowserVersion("92");
Map<String, Object> cloudOptions = new HashMap<>();
cloudOptions.put("build", myTestBuild);
cloudOptions.put("name", myTestName);
browserOptions.setCapability("cloud: options", cloudOptions);
WebDriver driver = new RemoteWebDriver(new URL(cloudUrl), browserOptions);
capabilities = {
  browserName:  'firefox',
  browserVersion:  '92',
  platformName:  'Windows 10',
  'cloud: options':  {
     build:  myTestBuild,
     name:  myTestName,
  }
}
var browserOptions = new FirefoxOptions();
browserOptions.PlatformName = "Windows 10";
browserOptions.BrowserVersion = "92";
var cloudOptions = new Dictionary<string, object>();
cloudOptions.Add("build", myTestBuild);
cloudOptions.Add("name", myTestName);
browserOptions.AddAdditionalOption("cloud: options", cloudOptions);
var driver = new RemoteWebDriver(new Uri(CloudURL), browserOptions);
options = Selenium: : WebDriver: : Options.firefox
options.browser_version = 'latest'
options.platform_name = 'Windows 10'
cloud_options = {}
cloud_options[: build] = my_test_build
cloud_options[: name] = my_test_name
options.add_option('cloud: options', cloud_options)
driver = Selenium: : WebDriver.for : remote, url:  cloud_url, capabilities:  options
from selenium.webdriver.firefox.options import Options as FirefoxOptions
options = FirefoxOptions()
options.browser_version = '92'
options.platform_name = 'Windows 10'
cloud_options = {}
cloud_options['build'] = my_test_build
cloud_options['name'] = my_test_name
options.set_capability('cloud: options', cloud_options)
driver = webdriver.Remote(cloud_url, options=options)

在 Java 中查找元素工具方法

在 Java 绑定(FindsBy 接口)中 查找元素的工具方法已被删除 因为它们仅供内部使用.
以下代码示例更好地解释了这一点.

使用 findElement* 查找单个元素

Before

driver.findElementByClassName("className");
driver.findElementByCssSelector(".className");
driver.findElementById("elementId");
driver.findElementByLinkText("linkText");
driver.findElementByName("elementName");
driver.findElementByPartialLinkText("partialText");
driver.findElementByTagName("elementTagName");
driver.findElementByXPath("xPath");

After

driver.findElement(By.className("className"));
driver.findElement(By.cssSelector(".className"));
driver.findElement(By.id("elementId"));
driver.findElement(By.linkText("linkText"));
driver.findElement(By.name("elementName"));
driver.findElement(By.partialLinkText("partialText"));
driver.findElement(By.tagName("elementTagName"));
driver.findElement(By.xpath("xPath"));

使用 findElements* 查找多个元素

Before

driver.findElementsByClassName("className");
driver.findElementsByCssSelector(".className");
driver.findElementsById("elementId");
driver.findElementsByLinkText("linkText");
driver.findElementsByName("elementName");
driver.findElementsByPartialLinkText("partialText");
driver.findElementsByTagName("elementTagName");
driver.findElementsByXPath("xPath");

After

driver.findElements(By.className("className"));
driver.findElements(By.cssSelector(".className"));
driver.findElements(By.id("elementId"));
driver.findElements(By.linkText("linkText"));
driver.findElements(By.name("elementName"));
driver.findElements(By.partialLinkText("partialText"));
driver.findElements(By.tagName("elementTagName"));
driver.findElements(By.xpath("xPath"));

升级依赖

检查下面的小节以安装 Selenium 4 并升级您的项目依赖项.

Java

升级 Selenium 的过程取决于所使用的构建工具.
我们将涵盖Java 中最常见的 MavenGradle .
所需的最低 Java 版本仍然是 8.

Maven

Before

<dependencies>
  <!-- more dependencies ... -->
  <dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>3.141.59</version>
  </dependency>
  <!-- more dependencies ... -->
</dependencies>

After

<dependencies>
    <!-- more dependencies ... -->
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>4.0.0</version>
    </dependency>
    <!-- more dependencies ... -->
</dependencies>

进行更改后, 您可以在pom.xml 文件的同一目录中 执行 mvn clean compile .

Gradle

Before

plugins {
    id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
    mavenCentral()
}
dependencies {
    testImplementation 'org.junit.jupiter: junit-jupiter-api: 5.7.0'
    testRuntimeOnly 'org.junit.jupiter: junit-jupiter-engine: 5.7.0'
    implementation group:  'org.seleniumhq.selenium', name:  'selenium-java', version:  '3.141.59'
}
test {
    useJUnitPlatform()
}

After

plugins {
    id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
    mavenCentral()
}
dependencies {
    testImplementation 'org.junit.jupiter: junit-jupiter-api: 5.7.0'
    testRuntimeOnly 'org.junit.jupiter: junit-jupiter-engine: 5.7.0'
    implementation group:  'org.seleniumhq.selenium', name:  'selenium-java', version:  '4.0.0'
}
test {
    useJUnitPlatform()
}

进行更改后, 您可以在 build.gradle 文件所在的同一目录中 执行./gradlew clean build .

要检查所有 Java 版本, 您可以前往 MVNRepository .

C#

在 C# 中获取 Selenium 4 更新的 地方是 NuGet .
在下面包 Selenium.WebDriver 你可以获得更新到最新版本的说明.
在 Visual Studio 内部, 您可以通过 NuGet 包管理器执行:

PM> Install-Package Selenium.WebDriver -Version 4.0.0

Python

使用 Python 的最重要变化是所需的最低版本. Selenium 4 将至少需要 Python 3.7 或更高版本.
更多详细信息可以在 Python 包索引 .
基于命令行做升级的话, 你可以执行:

pip install selenium==4.0.0

Ruby

Selenium 4 的更新细节 可以在RubyGems中的gem发现 selenium-webdriver .
要安装最新版本, 您可以执行:

gem install selenium-webdriver

将以下内容添加到你的Gemfile:

gem 'selenium-webdriver', '~> 4.0.0'

JavaScript

可以在 Node 包管理器中找到 selenium-webdriver 包, npmjs .
Selenium 4 可以在 这里 找到.
要安装, 你可以执行:

npm install selenium-webdriver

或者, 更新你的 package.json 并运行 npm install :

{
  "name":  "selenium-tests",
  "version":  "1.0.0",
  "dependencies":  {
    "selenium-webdriver":  "^4.0.0"
  }
}

潜在错误和弃用消息

这是一组代码示例, 它们将有助于克服 您升级到 Selenium 4 后 可能会遇到的弃用消息.

Java

等待和超时

Timeout 中接收到的参数 已经从期望 (long time, TimeUnit unit) 切换到期待 (Duration duration) .

Before

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.manage().timeouts().setScriptTimeout(2, TimeUnit.MINUTES);
driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);

After

driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
driver.manage().timeouts().scriptTimeout(Duration.ofMinutes(2));
driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(10));

等待现在也期望不同的参数. WebDriverWait 现在期待一个 Duration 而不是以秒和毫秒为单位的 long 超时. FluentWait 的工具方法 withTimeoutpollingEvery 已经从期望 (long time, TimeUnit unit) 切换到 期待(Duration duration) .

Before

new WebDriverWait(driver, 3)
.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#id")));

Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
  .withTimeout(30, TimeUnit.SECONDS)
  .pollingEvery(5, TimeUnit.SECONDS)
  .ignoring(NoSuchElementException.class);

After

new WebDriverWait(driver, Duration.ofSeconds(3))
  .until(ExpectedConditions.elementToBeClickable(By.cssSelector("#id")));

  Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
  .withTimeout(Duration.ofSeconds(30))
  .pollingEvery(Duration.ofSeconds(5))
  .ignoring(NoSuchElementException.class);

合并capabilities不再改变调用对象

曾经可以将一组不同的capabilities合并到另一组中, 并且改变调用对象.
现在, 需要分配合并操作的结果.

Before

MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("platformVersion", "Windows 10");
FirefoxOptions options = new FirefoxOptions();
options.setHeadless(true);
options.merge(capabilities);

作为结果, options 对象被修改

After

MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("platformVersion", "Windows 10");
FirefoxOptions options = new FirefoxOptions();
options.setHeadless(true);
options = options.merge(capabilities);

merge 调用的结果需要分配给一个对象.

Firefox 遗留模式

在 GeckoDriver 出现之前, Selenium 项目有一个驱动程序实现来自动化 Firefox(版本 <48).
但是, 不再需要此实现, 因为在最新版本的 Firefox 中它不起作用.
为避免升级到 Selenium 4 时出现重大问题, setLegacy选项将显示为已弃用.
建议停止使用旧的实现 并且只依赖 GeckoDriver.
以下代码将显示在升级之后弃用的 setLegacy 行.

FirefoxOptions options = new FirefoxOptions();
options.setLegacy(true);

BrowserType

BrowserType 接口已经存在很长时间了, 但是其已变为弃用 且推荐使用新的 Browser 接口.

Before

MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("browserVersion", "92");
capabilities.setCapability("browserName", BrowserType.FIREFOX);

After

MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("browserVersion", "92");
capabilities.setCapability("browserName", Browser.FIREFOX);

C#

AddAdditionalCapability 已弃用

推荐使用AddAdditionalOption替代.
以下为一个示例:

Before

var browserOptions = new ChromeOptions();
browserOptions.PlatformName = "Windows 10";
browserOptions.BrowserVersion = "latest";
var cloudOptions = new Dictionary<string, object>();
browserOptions.AddAdditionalCapability("cloud: options", cloudOptions, true);

After

var browserOptions = new ChromeOptions();
browserOptions.PlatformName = "Windows 10";
browserOptions.BrowserVersion = "latest";
var cloudOptions = new Dictionary<string, object>();
browserOptions.AddAdditionalOption("cloud: options", cloudOptions);

Python

executable_path 已弃用, 请传递一个服务对象

在Selenium 4中,
您需要从服务对象设置驱动程序的 可执行路径 , 以防止出现弃用警告. (或者不要设置路径, 而是确保所需的驱动程序位于系统路径上.)

Before

from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
driver = webdriver.Chrome(executable_path=CHROMEDRIVER_PATH, options=options)

After

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
options = webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
service = ChromeService(executable_path=CHROMEDRIVER_PATH)
driver = webdriver.Chrome(service=service, options=options)

总结

我们已经过了升级到 Selenium 4 时要考虑的主要变化. 涵盖为升级准备测试代码时要涵盖的不同方面, 包括关于如何避免 使用Selenium新版本时 可能出现的潜在问题的建议.
最后, 我们还介绍了一系列您可能会遇到的升级问题, 分享这些问题的潜在修复方案.

本文最初发布于 https://saucelabs.com/resources/articles/how-to-upgrade-to-selenium-4

2 - Capabilities

2.1 - 共享的功能

这些capabilities用于所有浏览器.

为了通过Selenium WebDriver创建新会话, 本地端应向远程端提供基本功能. 远端使用相同的功能集来创建会话并描述当前会话功能.

WebDriver提供了每个远程端将 (或应该) 支持实现的功能. 以下是WebDriver支持的功能:

browserName:

此功能用于设置既定会话的 browserName . 如果未在远端安装指定的浏览器, 则会话创建将失败

browserVersion:

此功能是可选的, 用于在远程端设置可用的浏览器版本. 例如, 如果在仅安装80版本的系统上询问75版本的Chrome, 则会话创建将失败

页面加载策略

通过URL导航到新页面时, 默认情况下, Selenium将等待页面完全加载后再进行响应. 这对于初学者来说效果很好, 但是在加载大量第三方资源的页面上可能会导致较长的等待时间. 在这种情况下, 使用非默认策略可以使测试的执行速度更快, 但是也可能导致不稳定, 即页面上的元素随元素加载和大小变化而改变位置.

页面加载策略可以参考链接 document.readyState 如下述表格的描述:

策略准备完成的状态备注
normalcomplete默认情况下使用, 等待所有资源下载完成
eagerinteractiveDOM访问已准备就绪, 但其他资源 (如图像) 可能仍在加载中
noneAny完全不阻塞WebDriver

platformName

这标识了远端的操作系统, 获取 platformName 将返回操作系统的名称.

在基于云的供应者中, 设置 platformName 将在远程端设置操作系统.

acceptInsecureCerts

此功能检查在会话期间导航时 是否使用了过期的 (或) 无效的 TLS Certificate .

如果将功能设置为 false, 则页面浏览遇到任何域证书问题时, 将返回insecure certificate error . 如果设置为 true, 则浏览器将信任无效证书.

默认情况下, 此功能将信任所有自签名证书. 设置后, acceptInsecureCerts 功能将在整个会话中生效.

timeouts

WebDriver session 具有一定的 session timeout 间隔, 在此间隔内, 用户可以控制执行脚本或从浏览器检索信息的行为.

每个会话超时都配置有不同 timeouts 的组合, 如下所述:

Script Timeout:

指定在当前浏览上下文中, 中断正在执行脚本的时机. WebDriver创建新会话时, 将设置默认的超时时间为 30,000 .

Page Load Timeout:

指定在当前浏览上下文中, 加载网页的时间间隔. WebDriver创建新会话时, 默认设置超时时间为 300,000 . 如果页面加载限制了给定 (或默认) 的时间范围, 则该脚本将被 TimeoutException 停止.

Implicit Wait Timeout

指定在定位元素时, 等待隐式元素定位策略的时间. WebDriver创建新会话时, 将设置默认超时时间为 0 .

unhandledPromptBehavior

指定当前会话 user prompt handler 的状态. 默认为 dismiss and notify state .

User Prompt Handler

这定义了在远端出现用户提示时必须采取的措施. 该行为由unhandledPromptBehavior 功能定义, 具有以下状态:

  • dismiss
  • accept
  • dismiss and notify
  • accept and notify
  • ignore

setWindowRect

此命令更改当前浏览上下文中窗口的大小和位置. 此命令作为 getWindowRect 对应的设置方法, 该命令接受 width, height, x, y 作为 可选 参数.

在自动化期间, 当前浏览上下文将与描述浏览器窗口可见性状态的窗口状态相关联. 窗口状态为

  • maximized
  • minimized
  • normal
  • fullscreen

设置 WidthHeight 不能保证结果窗口的大小一定完全匹配所请求的窗口大小. 这是因为某些驱动程序可能无法以单像素为单位调整大小. 因此, 通过 getWindowRect 获取窗口状态 (或详细信息) 可能与浏览器设置的值不匹配.

strictFileInteractability

新功能用于是否对 类型为文件的输入(input type=file) 元素进行严格的交互性检查. 默认关闭严格性检查, 在将 元素的Send Keys 方法作用于隐藏的文件上传时, 会有控制方面的行为区别.

proxy

代理服务器充当客户端和服务器之间的请求中介. 简述而言, 流量将通过代理服务器流向您请求的地址, 然后返回.

使用代理服务器用于Selenium的自动化脚本, 可能对以下方面有益:

  • 捕获网络流量
  • 模拟网站后端响应
  • 在复杂的网络拓扑结构或严格的公司限制/政策下访问目标站点.

如果您在公司环境中, 并且浏览器无法连接到URL, 则最有可能是因为环境, 需要借助代理进行访问.

Selenium WebDriver提供了如下设置代理的方法

import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class proxyTest {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.setHttpProxy("<HOST:PORT>");
ChromeOptions options = new ChromeOptions();
options.setCapability("proxy", proxy);
WebDriver driver = new ChromeDriver(options);
driver.get("https://www.google.com/");
driver.manage().window().maximize();
driver.quit();
}
}
from selenium import webdriver

PROXY = "<HOST:PORT>"
webdriver.DesiredCapabilities.FIREFOX['proxy'] = {
"httpProxy": PROXY,
"ftpProxy": PROXY,
"sslProxy": PROXY,
"proxyType": "MANUAL",

}

with webdriver.Firefox() as driver:
# Open URL
driver.get("https://selenium.dev")
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

public class ProxyTest{
public static void Main() {
ChromeOptions options = new ChromeOptions();
Proxy proxy = new Proxy();
proxy.Kind = ProxyKind.Manual;
proxy.IsAutoDetect = false;
proxy.SslProxy = "<HOST:PORT>";
options.Proxy = proxy;
options.AddArgument("ignore-certificate-errors");
IWebDriver driver = new ChromeDriver(options);
driver.Navigate().GoToUrl("https://www.selenium.dev/");
}
}
# this code was written with Selenium 4

proxy = Selenium::WebDriver::Proxy.new(http: '<HOST:PORT>')
cap   = Selenium::WebDriver::Remote::Capabilities.chrome(proxy: proxy)

driver = Selenium::WebDriver.for(:chrome, capabilities: cap)
driver.get('http://google.com')
let webdriver = require('selenium-webdriver');
let chrome = require('selenium-webdriver/chrome');
let proxy = require('selenium-webdriver/proxy');
let opts = new chrome.Options();

(async function example() {
opts.setProxy(proxy.manual({http: '<HOST:PORT>'}));
let driver = new webdriver.Builder()
.forBrowser('chrome')
.setChromeOptions(opts)
.build();
try {
await driver.get("https://selenium.dev");
}
finally {
await driver.quit();
}
}());
import org.openqa.selenium.Proxy
import org.openqa.selenium.WebDriver
import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.chrome.ChromeOptions

class proxyTest {
fun main() {

        val proxy = Proxy()
        proxy.setHttpProxy("<HOST:PORT>")
        val options = ChromeOptions()
        options.setCapability("proxy", proxy)
        val driver: WebDriver = ChromeDriver(options)
        driver["https://www.google.com/"]
        driver.manage().window().maximize()
        driver.quit()
    }
}

2.2 - 特定的Chromium浏览器Capabilities

这些capabilities基于特定的Chromium浏览器.

这些Capabilities应用于:

  • Chrome
  • Chromium
  • Edge

2.3 - Firefox浏览器特定的Capabilities

这些capabilities基于特定的Firefox浏览器.

使用FirefoxOptions定义功能

FirefoxOptions 是为Firefox浏览器定义功能(Capabilities)的新方法,通常应优先使用预期功能(DesiredCapabilities).

FirefoxOptions options = new FirefoxOptions();
options.addPreference("network.proxy.type", 0);
driver = new RemoteWebDriver(options);
  
from selenium.webdriver.firefox.options import Options
options = Options()
options.headless = True
driver = webdriver.Firefox(options=options)
  
var options = new FirefoxOptions();
options.Proxy.Kind = ProxyKind.Direct;
var driver = new FirefoxDriver(options);
  
require 'selenium-webdriver'
opts = Selenium::WebDriver::Firefox::Options.new(args: ['-headless'])
driver = Selenium::WebDriver.for(:firefox, options: opts)
  
const { Builder } = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');

const options = new firefox.Options();
options.headless();
const driver = new Builder()
    .forBrowser('firefox')
    .setFirefoxOptions(options)
    .build();
  
val options = new FirefoxOptions()
options.addPreference("network.proxy.type", 0)
driver = RemoteWebDriver(options)
  

设置自定义配置文件

可以为Firefox创建自定义配置文件, 如下所示.

FirefoxProfile profile = new FirefoxProfile();
FirefoxOptions options = new FirefoxOptions();
options.setProfile(profile);
driver = new RemoteWebDriver(options);
  
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
options=Options()
firefox_profile = FirefoxProfile()
firefox_profile.set_preference("javascript.enabled", False)
options.profile = firefox_profile
  
var options = new FirefoxOptions();
var profile = new FirefoxProfile();
options.Profile = profile;
var driver = new RemoteWebDriver(options);
  
profile = Selenium::WebDriver::Firefox::Profile.new
profile['browser.download.dir'] = "/tmp/webdriver-downloads"
options = Selenium::WebDriver::Firefox::Options.new(profile: profile)
driver = Selenium::WebDriver.for :firefox, options: options
  
const { Builder } = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');

const options = new firefox.Options();
let profile = '/path to custom profile';
options.setProfile(profile);
const driver = new Builder()
    .forBrowser('firefox')
    .setFirefoxOptions(options)
    .build();
  
val options = FirefoxOptions()
options.profile = FirefoxProfile()
driver = RemoteWebDriver(options)
  

2.4 - Internet Explorer浏览器特定的Capabilities

这些capabilities基于特定的Internet Explorer浏览器.

fileUploadDialogTimeout

在某些环境中, 当打开文件上传对话框时, Internet Explorer可能会超时. IEDriver的默认超时为1000毫秒, 但您可以使用fileUploadDialogTimeout功能来增加超时时间.

InternetExplorerOptions options = new InternetExplorerOptions();
options.waitForUploadDialogUpTo(Duration.ofSeconds(2));
WebDriver driver = new RemoteWebDriver(options); 
  
from selenium import webdriver

options = webdriver.IeOptions()
options.file_upload_dialog_timeout = 2000
driver = webdriver.Ie(options=options)

driver.get("http://www.google.com")

driver.quit()
  
var options = new InternetExplorerOptions();
options.FileUploadDialogTimeout = TimeSpan.FromMilliseconds(2000);
var driver = new RemoteWebDriver(options);
  
options = Selenium::WebDriver::IE::Options.new
options.file_upload_dialog_timeout = 2000
driver = Selenium::WebDriver.for(:ie, options: options)
  
const ie = require('selenium-webdriver/ie');
let options = new ie.Options().fileUploadDialogTimeout(2000);
let driver = await Builder()
          .setIeOptions(options)
          .build();  
  
val options = InternetExplorerOptions()
options.waitForUploadDialogUpTo(Duration.ofSeconds(2))
val driver = RemoteWebDriver(options)
  

ensureCleanSession

设置为 true时, 此功能将清除InternetExplorer所有正在运行实例的 缓存, 浏览器历史记录和Cookies (包括手动启动或由驱动程序启动的实例) . 默认情况下,此设置为 false.

使用此功能将导致启动浏览器时性能下降, 因为驱动程序将等待直到缓存清除后再启动IE浏览器.

此功能接受一个布尔值作为参数.

InternetExplorerOptions options = new InternetExplorerOptions();
options.destructivelyEnsureCleanSession();
WebDriver driver = new RemoteWebDriver(options);
  
from selenium import webdriver

options = webdriver.IeOptions()
options.ensure_clean_session = True
driver = webdriver.Ie(options=options)

driver.get("http://www.google.com")

driver.quit()
  
var options = new InternetExplorerOptions();
options.EnsureCleanSession = true;
var driver = new RemoteWebDriver(options);
  
options = Selenium::WebDriver::IE::Options.new
options.ensure_clean_session = true
driver = Selenium::WebDriver.for(:ie, options: options)
  
const ie = require('selenium-webdriver/ie');
let options = new ie.Options().ensureCleanSession(true);
let driver = await Builder()
          .setIeOptions(options)
          .build(); 
  
val options = InternetExplorerOptions()
options.destructivelyEnsureCleanSession()
val driver = RemoteWebDriver(options)
  

ignoreZoomSetting

InternetExplorer驱动程序期望浏览器的缩放级别为100%, 否则驱动程序将可能抛出异常. 通过将 ignoreZoomSetting 设置为 true, 可以禁用此默认行为.

此功能接受一个布尔值作为参数.

InternetExplorerOptions options = new InternetExplorerOptions();
options.ignoreZoomSettings();
WebDriver driver = new RemoteWebDriver(options);
  
from selenium import webdriver

options = webdriver.IeOptions()
options.ignore_zoom_level = True
driver = webdriver.Ie(options=options)

driver.get("http://www.google.com")

driver.quit()
  
var options = new InternetExplorerOptions();
options.IgnoreZoomLevel = true;
var driver = new RemoteWebDriver(options);
  
options = Selenium::WebDriver::IE::Options.new
options.ignore_zoom_level = true
driver = Selenium::WebDriver.for(:ie, options: options)
  
const ie = require('selenium-webdriver/ie');
let options = new ie.Options().ignoreZoomSetting(true);
let driver = await Builder()
          .setIeOptions(options)
          .build(); 
  
val options = InternetExplorerOptions()
options.ignoreZoomSettings()
val driver = RemoteWebDriver(options)
  

ignoreProtectedModeSettings

启动新的IE会话时是否跳过 保护模式 检查.

如果未设置, 并且所有区域的 保护模式 设置都不同, 则驱动程序将可能引发异常.

如果将功能设置为 true, 则测试可能会变得不稳定, 无响应, 或者浏览器可能会挂起. 但是, 到目前为止, 这仍然是第二好的选择, 并且第一选择应该 始终 是手动实际设置每个区域的保护模式设置. 如果用户正在使用此属性, 则只会给予 “尽力而为” 的支持.

此功能接受一个布尔值作为参数.

InternetExplorerOptions options = new InternetExplorerOptions();
options.introduceFlakinessByIgnoringSecurityDomains();
WebDriver driver = new RemoteWebDriver(options);
  
from selenium import webdriver

options = webdriver.IeOptions()
options.ignore_protected_mode_settings = True
driver = webdriver.Ie(options=options)

driver.get("http://www.google.com")

driver.quit()
  
var options = new InternetExplorerOptions();
options.IntroduceInstabilityByIgnoringProtectedModeSettings = true;
var driver = new RemoteWebDriver(options);
  
options = Selenium::WebDriver::IE::Options.new
options.ignore_protected_mode_settings = true
driver = Selenium::WebDriver.for(:ie, options: options)
  
const ie = require('selenium-webdriver/ie');
let options = new ie.Options().introduceFlakinessByIgnoringProtectedModeSettings(true);
let driver = await Builder()
          .setIeOptions(options)
          .build(); 
  
val options = InternetExplorerOptions()
options.introduceFlakinessByIgnoringSecurityDomains()
val driver = RemoteWebDriver(options)
  

silent

设置为 true时, 此功能将禁止IEDriverServer的诊断输出.

此功能接受一个布尔值作为参数.

InternetExplorerOptions options = new InternetExplorerOptions();
options.setCapability("silent", true);
WebDriver driver = new InternetExplorerDriver(options);
  
from selenium import webdriver

options = webdriver.IeOptions()
options.set_capability("silent", True)
driver = webdriver.Ie(options=options)

driver.get("http://www.google.com")

driver.quit()
  
InternetExplorerOptions options = new InternetExplorerOptions();
options.AddAdditionalInternetExplorerOption("silent", true);
IWebDriver driver = new InternetExplorerDriver(options);
  
    # Please raise a PR to add code sample
  
const {Builder,By, Capabilities} = require('selenium-webdriver');
let caps = Capabilities.ie();
caps.set('silent', true);

(async function example() {
    let driver = await new Builder()
        .forBrowser('internet explorer')
        .withCapabilities(caps)
        .build();
    try {
        await driver.get('http://www.google.com/ncr');
    }
    finally {
        await driver.quit();
    }
})();
  
import org.openqa.selenium.Capabilities
import org.openqa.selenium.ie.InternetExplorerDriver
import org.openqa.selenium.ie.InternetExplorerOptions

fun main() {
    val options = InternetExplorerOptions()
    options.setCapability("silent", true)
    val driver = InternetExplorerDriver(options)
    try {
        driver.get("https://google.com/ncr")
        val caps = driver.getCapabilities()
        println(caps)
    } finally {
        driver.quit()
    }
}
  

IE 命令行选项

Internet Explorer包含几个命令行选项, 使您可以进行故障排除和配置浏览器.

下面介绍了一些受支持的命令行选项

  • -private : 用于在私有浏览模式下启动IE. 这适用于IE 8和更高版本.

  • -k : 在kiosk模式下启动Internet Explorer. 浏览器在一个最大化的窗口中打开, 该窗口不显示地址栏, 导航按钮或状态栏.

  • -extoff : 在无附加模式下启动IE. 此选项专门用于解决浏览器加载项问题. 在IE 7和更高版本中均可使用.

注意: forceCreateProcessApi 应该启用命令行参数才能正常工作.

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.ie.InternetExplorerOptions;

public class ieTest {
    public static void main(String[] args) {
        InternetExplorerOptions options = new InternetExplorerOptions();
        options.useCreateProcessApiToLaunchIe();
        options.addCommandSwitches("-k");
        InternetExplorerDriver driver = new InternetExplorerDriver(options);
        try {
            driver.get("https://google.com/ncr");
            Capabilities caps = driver.getCapabilities();
            System.out.println(caps);
        } finally {
            driver.quit();
        }
    }
}
  
from selenium import webdriver

options = webdriver.IeOptions()
options.add_argument('-private')
options.force_create_process_api = True
driver = webdriver.Ie(options=options)

driver.get("http://www.google.com")

driver.quit()
  
using System;
using OpenQA.Selenium;
using OpenQA.Selenium.IE;

namespace ieTest {
 class Program {
  static void Main(string[] args) {
   InternetExplorerOptions options = new InternetExplorerOptions();
   options.ForceCreateProcessApi = true;
   options.BrowserCommandLineArguments = "-k";
   IWebDriver driver = new InternetExplorerDriver(options);
   driver.Url = "https://google.com/ncr";
  }
 }
}
  
require 'selenium-webdriver'
options = Selenium::WebDriver::IE::Options.new
options.force_create_process_api = true
options.add_argument('-k')
driver = Selenium::WebDriver.for(:ie, options: options)

begin
  driver.get 'https://google.com'
  puts(driver.capabilities.to_json)
ensure
  driver.quit
end
  
const ie = require('selenium-webdriver/ie');
let options = new ie.Options();
options.addBrowserCommandSwitches('-k');
options.addBrowserCommandSwitches('-private');
options.forceCreateProcessApi(true);

driver = await env.builder()
          .setIeOptions(options)
          .build();
  
import org.openqa.selenium.Capabilities
import org.openqa.selenium.ie.InternetExplorerDriver
import org.openqa.selenium.ie.InternetExplorerOptions

fun main() {
    val options = InternetExplorerOptions()
    options.useCreateProcessApiToLaunchIe()
    options.addCommandSwitches("-k")
    val driver = InternetExplorerDriver(options)
    try {
        driver.get("https://google.com/ncr")
        val caps = driver.getCapabilities()
        println(caps)
    } finally {
        driver.quit()
    }
}
  

forceCreateProcessApi

强制使用CreateProcess API启动Internet Explorer. 默认值为false.

对于IE 8及更高版本, 此选项要求将 “TabProcGrowth” 注册表值设置为0.

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.ie.InternetExplorerOptions;

public class ieTest {
    public static void main(String[] args) {
        InternetExplorerOptions options = new InternetExplorerOptions();
        options.useCreateProcessApiToLaunchIe();
        InternetExplorerDriver driver = new InternetExplorerDriver(options);
        try {
            driver.get("https://google.com/ncr");
            Capabilities caps = driver.getCapabilities();
            System.out.println(caps);
        } finally {
            driver.quit();
        }
    }
}
  
from selenium import webdriver

options = webdriver.IeOptions()
options.force_create_process_api = True
driver = webdriver.Ie(options=options)

driver.get("http://www.google.com")

driver.quit()
  
using System;
using OpenQA.Selenium;
using OpenQA.Selenium.IE;

namespace ieTest {
 class Program {
  static void Main(string[] args) {
   InternetExplorerOptions options = new InternetExplorerOptions();
   options.ForceCreateProcessApi = true;
   IWebDriver driver = new InternetExplorerDriver(options);
   driver.Url = "https://google.com/ncr";
  }
 }
}
  
require 'selenium-webdriver'
options = Selenium::WebDriver::IE::Options.new
options.force_create_process_api = true
driver = Selenium::WebDriver.for(:ie, options: options)

begin
  driver.get 'https://google.com'
  puts(driver.capabilities.to_json)
ensure
  driver.quit
end
  
const ie = require('selenium-webdriver/ie');
let options = new ie.Options();
options.forceCreateProcessApi(true);

driver = await env.builder()
          .setIeOptions(options)
          .build();
  
import org.openqa.selenium.Capabilities
import org.openqa.selenium.ie.InternetExplorerDriver
import org.openqa.selenium.ie.InternetExplorerOptions

fun main() {
    val options = InternetExplorerOptions()
    options.useCreateProcessApiToLaunchIe()
    val driver = InternetExplorerDriver(options)
    try {
        driver.get("https://google.com/ncr")
        val caps = driver.getCapabilities()
        println(caps)
    } finally {
        driver.quit()
    }
}
  

2.5 - Safari浏览器特定的Capabilities

这些capabilities基于特定的Safari浏览器.

3 - 浏览器

获取浏览器信息

获取标题

从浏览器中读取当前页面的标题:

driver.getTitle();
driver.title
driver.Title;
driver.title
await driver.getTitle();
driver.title

获取当前 URL

您可以从浏览器的地址栏读取当前的 URL,使用:

driver.getCurrentUrl();
driver.current_url
driver.Url;
driver.current_url
await driver.getCurrentUrl();
driver.currentUrl

3.1 - 浏览器导航

打开网站

启动浏览器后你要做的第一件事就是打开你的网站。这可以通过一行代码实现:

// 简便的方法
driver.get("https://selenium.dev");

// 更长的方法
driver.navigate().to("https://selenium.dev");
driver.get("https://selenium.dev")
driver.Navigate().GoToUrl(@"https://selenium.dev");
    # 简便的方法
driver.get 'https://selenium.dev'

    # 更长的方法
driver.navigate.to 'https://selenium.dev'
await driver.get('https://selenium.dev');
// 简便的方法
driver.get("https://selenium.dev")

// 更长的方法
driver.navigate().to("https://selenium.dev")

后退

按下浏览器的后退按钮:

driver.navigate().back();
driver.back()
driver.Navigate().Back();
driver.navigate.back
await driver.navigate().back();
driver.navigate().back() 

前进

按下浏览器的前进键:

driver.navigate().forward();
driver.forward()
driver.Navigate().Forward();
driver.navigate.forward
await driver.navigate().forward();
driver.navigate().forward()

刷新

刷新当前页面:

driver.navigate().refresh();
driver.refresh()
driver.Navigate().Refresh();
driver.navigate.refresh
await driver.navigate().refresh();
driver.navigate().refresh()

3.2 - JavaScript 警告框,提示框和确认框

WebDriver提供了一个API, 用于处理JavaScript提供的三种类型的原生弹窗消息. 这些弹窗由浏览器提供限定的样式.

Alerts 警告框

其中最基本的称为警告框, 它显示一条自定义消息, 以及一个用于关闭该警告的按钮, 在大多数浏览器中标记为"确定"(OK). 在大多数浏览器中, 也可以通过按"关闭"(close)按钮将其关闭, 但这始终与“确定”按钮具有相同的作用. 查看样例警告框.

WebDriver可以从弹窗获取文本并接受或关闭这些警告.

//Click the link to activate the alert
driver.findElement(By.linkText("See an example alert")).click();

//Wait for the alert to be displayed and store it in a variable
Alert alert = wait.until(ExpectedConditions.alertIsPresent());

//Store the alert text in a variable
String text = alert.getText();

//Press the OK button
alert.accept();
  
# Click the link to activate the alert
driver.find_element(By.LINK_TEXT, "See an example alert").click()

# Wait for the alert to be displayed and store it in a variable
alert = wait.until(expected_conditions.alert_is_present())

# Store the alert text in a variable
text = alert.text

# Press the OK button
alert.accept()
  
//Click the link to activate the alert
driver.FindElement(By.LinkText("See an example alert")).Click();

//Wait for the alert to be displayed and store it in a variable
IAlert alert = wait.Until(ExpectedConditions.AlertIsPresent());

//Store the alert text in a variable
string text = alert.Text;

//Press the OK button
alert.Accept();
  
# Click the link to activate the alert
driver.find_element(:link_text, 'See an example alert').click

# Store the alert reference in a variable
alert = driver.switch_to.alert

# Store the alert text in a variable
alert_text = alert.text

# Press on OK button
alert.accept
  
//Click the link to activate the alert
await driver.findElement(By.linkText('See an example alert')).click();

// Wait for the alert to be displayed
await driver.wait(until.alertIsPresent());

// Store the alert in a variable
let alert = await driver.switchTo().alert();

//Store the alert text in a variable
let alertText = await alert.getText();

//Press the OK button
await alert.accept();

// Note: To use await, the above code should be inside an async function
  
//Click the link to activate the alert
driver.findElement(By.linkText("See an example alert")).click()

//Wait for the alert to be displayed and store it in a variable
val alert = wait.until(ExpectedConditions.alertIsPresent())

//Store the alert text in a variable
val text = alert.getText()

//Press the OK button
alert.accept()
  

Confirm 确认框

确认框类似于警告框, 不同之处在于用户还可以选择取消消息. 查看样例确认框.

此示例还呈现了警告的另一种实现:

//Click the link to activate the alert
driver.findElement(By.linkText("See a sample confirm")).click();

//Wait for the alert to be displayed
wait.until(ExpectedConditions.alertIsPresent());

//Store the alert in a variable
Alert alert = driver.switchTo().alert();

//Store the alert in a variable for reuse
String text = alert.getText();

//Press the Cancel button
alert.dismiss();
  
# Click the link to activate the alert
driver.find_element(By.LINK_TEXT, "See a sample confirm").click()

# Wait for the alert to be displayed
wait.until(expected_conditions.alert_is_present())

# Store the alert in a variable for reuse
alert = driver.switch_to.alert

# Store the alert text in a variable
text = alert.text

# Press the Cancel button
alert.dismiss()
  
//Click the link to activate the alert
driver.FindElement(By.LinkText("See a sample confirm")).Click();

//Wait for the alert to be displayed
wait.Until(ExpectedConditions.AlertIsPresent());

//Store the alert in a variable
IAlert alert = driver.SwitchTo().Alert();

//Store the alert in a variable for reuse
string text = alert.Text;

//Press the Cancel button
alert.Dismiss();
  
# Click the link to activate the alert
driver.find_element(:link_text, 'See a sample confirm').click

# Store the alert reference in a variable
alert = driver.switch_to.alert

# Store the alert text in a variable
alert_text = alert.text

# Press on Cancel button
alert.dismiss
  
//Click the link to activate the alert
await driver.findElement(By.linkText('See a sample confirm')).click();

// Wait for the alert to be displayed
await driver.wait(until.alertIsPresent());

// Store the alert in a variable
let alert = await driver.switchTo().alert();

//Store the alert text in a variable
let alertText = await alert.getText();

//Press the Cancel button
await alert.dismiss();

// Note: To use await, the above code should be inside an async function
  
//Click the link to activate the alert
driver.findElement(By.linkText("See a sample confirm")).click()

//Wait for the alert to be displayed
wait.until(ExpectedConditions.alertIsPresent())

//Store the alert in a variable
val alert = driver.switchTo().alert()

//Store the alert in a variable for reuse
val text = alert.text

//Press the Cancel button
alert.dismiss()
  

Prompt 提示框

提示框与确认框相似, 不同之处在于它们还包括文本输入. 与处理表单元素类似, 您可以使用WebDriver的sendKeys来填写响应. 这将完全替换占位符文本. 按下取消按钮将不会提交任何文本. 查看样例提示框.

//Click the link to activate the alert
driver.findElement(By.linkText("See a sample prompt")).click();

//Wait for the alert to be displayed and store it in a variable
Alert alert = wait.until(ExpectedConditions.alertIsPresent());

//Type your message
alert.sendKeys("Selenium");

//Press the OK button
alert.accept();
  
# Click the link to activate the alert
driver.find_element(By.LINK_TEXT, "See a sample prompt").click()

# Wait for the alert to be displayed
wait.until(expected_conditions.alert_is_present())

# Store the alert in a variable for reuse
alert = Alert(driver)

# Type your message
alert.send_keys("Selenium")

# Press the OK button
alert.accept()
  
//Click the link to activate the alert
driver.FindElement(By.LinkText("See a sample prompt")).Click();

//Wait for the alert to be displayed and store it in a variable
IAlert alert = wait.Until(ExpectedConditions.AlertIsPresent());

//Type your message
alert.SendKeys("Selenium");

//Press the OK button
alert.Accept();
  
# Click the link to activate the alert
driver.find_element(:link_text, 'See a sample prompt').click

# Store the alert reference in a variable
alert = driver.switch_to.alert

# Type a message
alert.send_keys("selenium")

# Press on Ok button
alert.accept
  
//Click the link to activate the alert
await driver.findElement(By.linkText('See a sample prompt')).click();

// Wait for the alert to be displayed
await driver.wait(until.alertIsPresent());

// Store the alert in a variable
let alert = await driver.switchTo().alert();

//Type your message
await alert.sendKeys("Selenium");

//Press the OK button
await alert.accept();

//Note: To use await, the above code should be inside an async function
  
//Click the link to activate the alert
driver.findElement(By.linkText("See a sample prompt")).click()

//Wait for the alert to be displayed and store it in a variable
val alert = wait.until(ExpectedConditions.alertIsPresent())

//Type your message
alert.sendKeys("Selenium")

//Press the OK button
alert.accept()
  

3.3 - 同cookies一起工作

Cookie是从网站发送并存储在您的计算机中的一小段数据. Cookies主要用于识别用户并加载存储的信息.

WebDriver API提供了一种使用内置的方法与Cookie进行交互:

这个方法常常用于将cookie添加到当前访问的上下文中. 添加Cookie仅接受一组已定义的可序列化JSON对象. 这里 是一个链接, 用于描述可接受的JSON键值的列表

首先, 您需要位于有效Cookie的域上. 如果您在开始与网站进行交互之前尝试预设cookie, 并且您的首页很大或需要一段时间才能加载完毕, 则可以选择在网站上找到一个较小的页面 (通常404页很小, 例如 http://example.com/some404page)

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;

public class addCookie {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        try {
            driver.get("http://www.example.com");

            // Adds the cookie into current browser context
            driver.manage().addCookie(new Cookie("key", "value"));
        } finally {
            driver.quit();
        }
    }
}
  
from selenium import webdriver

driver = webdriver.Chrome()

driver.get("http://www.example.com")

# Adds the cookie into current browser context
driver.add_cookie({"name": "key", "value": "value"})
  
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace AddCookie {
 class AddCookie {
  public static void Main(string[] args) {
   IWebDriver driver = new ChromeDriver();
   try {
    // Navigate to Url
    driver.Navigate().GoToUrl("https://example.com");

    // Adds the cookie into current browser context
    driver.Manage().Cookies.AddCookie(new Cookie("key", "value"));
   } finally {
    driver.Quit();
   }
  }
 }
}
  
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome

begin
  driver.get 'https://www.example.com'
  
  # Adds the cookie into current browser context
  driver.manage.add_cookie(name: "key", value: "value")
ensure
  driver.quit
end
  
const {Builder} = require('selenium-webdriver');
(async function example() {
  let driver = new Builder()
    .forBrowser('chrome')
    .build();

  await driver.get('https://www.example.com');
  // set a cookie on the current domain
  await driver.manage().addCookie({name:'key', value: 'value'});
  await driver.quit();
})();
import org.openqa.selenium.Cookie
import org.openqa.selenium.chrome.ChromeDriver

fun main() {
    val driver = ChromeDriver()
    try {
        driver.get("https://example.com")

        // Adds the cookie into current browser context
        driver.manage().addCookie(Cookie("key", "value"))
    } finally {
        driver.quit()
    }
}  
  

此方法返回与cookie名称匹配的序列化cookie数据中所有关联的cookie.

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;

public class getCookieNamed {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        try {
            driver.get("http://www.example.com");
            driver.manage().addCookie(new Cookie("foo", "bar"));

            // Get cookie details with named cookie 'foo'
            Cookie cookie1 = driver.manage().getCookieNamed("foo");
            System.out.println(cookie1);
        } finally {
            driver.quit();
        }
    }
}
  
from selenium import webdriver

driver = webdriver.Chrome()

# Navigate to url
driver.get("http://www.example.com")

# Adds the cookie into current browser context
driver.add_cookie({"name": "foo", "value": "bar"})

# Get cookie details with named cookie 'foo'
print(driver.get_cookie("foo"))
  
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace GetCookieNamed {
 class GetCookieNamed {
  public static void Main(string[] args) {
   IWebDriver driver = new ChromeDriver();
   try {
    // Navigate to Url
    driver.Navigate().GoToUrl("https://example.com");
    driver.Manage().Cookies.AddCookie(new Cookie("foo", "bar"));

    // Get cookie details with named cookie 'foo'
    var cookie = driver.Manage().Cookies.GetCookieNamed("foo");
    System.Console.WriteLine(cookie);
   } finally {
    driver.Quit();
   }
  }
 }
}
  
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome

begin
  driver.get 'https://www.example.com'
  driver.manage.add_cookie(name: "foo", value: "bar")

  # Get cookie details with named cookie 'foo'
  puts driver.manage.cookie_named('foo')
ensure
  driver.quit
end
  
const {Builder} = require('selenium-webdriver');

(async function getCookieByName() {
  let driver = new Builder()
    .forBrowser('chrome')
    .build();

  await driver.get('https://www.example.com');
  // set a cookie on the current domain
  await driver.manage().addCookie({name:'foo', value: 'bar'});
  // Get cookie details with named cookie 'foo'
  await driver.manage().getCookie('foo').then(function (cookie) {
    console.log('cookie details => ', cookie);
  });
  await driver.quit();
})();
import org.openqa.selenium.Cookie
import org.openqa.selenium.chrome.ChromeDriver

fun main() {
    val driver = ChromeDriver()
    try {
        driver.get("https://example.com")
        driver.manage().addCookie(Cookie("foo", "bar"))

        // Get cookie details with named cookie 'foo'
        val cookie = driver.manage().getCookieNamed("foo")
        println(cookie)
    } finally {
        driver.quit()
    }
}  
  

获取全部 Cookies

此方法会针对当前访问上下文返回“成功的序列化cookie数据”. 如果浏览器不再可用, 则返回错误.

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.Set;

public class getAllCookies {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        try {
            driver.get("http://www.example.com");
            // Add few cookies
            driver.manage().addCookie(new Cookie("test1", "cookie1"));
            driver.manage().addCookie(new Cookie("test2", "cookie2"));

            // Get All available cookies
            Set<Cookie> cookies = driver.manage().getCookies();
            System.out.println(cookies);
        } finally {
            driver.quit();
        }
    }
}
  
from selenium import webdriver

driver = webdriver.Chrome()

# Navigate to url
driver.get("http://www.example.com")

driver.add_cookie({"name": "test1", "value": "cookie1"})
driver.add_cookie({"name": "test2", "value": "cookie2"})

# Get all available cookies
print(driver.get_cookies())
  
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace GetAllCookies {
 class GetAllCookies {
  public static void Main(string[] args) {
   IWebDriver driver = new ChromeDriver();
   try {
    // Navigate to Url
    driver.Navigate().GoToUrl("https://example.com");
    driver.Manage().Cookies.AddCookie(new Cookie("test1", "cookie1"));
    driver.Manage().Cookies.AddCookie(new Cookie("test2", "cookie2"));

    // Get All available cookies
    var cookies = driver.Manage().Cookies.AllCookies;
   } finally {
    driver.Quit();
   }
  }
 }
}
  
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome

begin
  driver.get 'https://www.example.com'
  driver.manage.add_cookie(name: "test1", value: "cookie1")
  driver.manage.add_cookie(name: "test2", value: "cookie2")

  # Get all available cookies
  puts driver.manage.all_cookies
ensure
  driver.quit
end
  
const {Builder} = require('selenium-webdriver');

(async function getAllCookies() {
  let driver = new Builder()
    .forBrowser('chrome')
    .build();

  await driver.get('https://www.example.com');
  // Add few cookies
  await driver.manage().addCookie({name:'test1', value:'cookie1'});
  await driver.manage().addCookie({name:'test2', value:'cookie2'});
  // Get all Available cookies
  await driver.manage().getCookies().then(function (cookies) {
    console.log('cookie details => ', cookies);
  });
  await driver.quit()
})();
import org.openqa.selenium.Cookie
import org.openqa.selenium.chrome.ChromeDriver

fun main() {
    val driver = ChromeDriver()
    try {
        driver.get("https://example.com")
        driver.manage().addCookie(Cookie("test1", "cookie1"))
        driver.manage().addCookie(Cookie("test2", "cookie2"))

        // Get All available cookies
        val cookies = driver.manage().cookies
        println(cookies)
    } finally {
        driver.quit()
    }
}  
  

此方法删除与提供的cookie名称匹配的cookie数据.

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;

public class deleteCookie {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        try {
            driver.get("http://www.example.com");
            driver.manage().addCookie(new Cookie("test1", "cookie1"));
            Cookie cookie1 = new Cookie("test2", "cookie2");
            driver.manage().addCookie(cookie1);

            // delete a cookie with name 'test1'
            driver.manage().deleteCookieNamed("test1");

            /*
             Selenium Java bindings also provides a way to delete
             cookie by passing cookie object of current browsing context
             */
            driver.manage().deleteCookie(cookie1);
        } finally {
            driver.quit();
        }
    }
}
  
from selenium import webdriver
driver = webdriver.Chrome()

# Navigate to url
driver.get("http://www.example.com")
driver.add_cookie({"name": "test1", "value": "cookie1"})
driver.add_cookie({"name": "test2", "value": "cookie2"})

# Delete a cookie with name 'test1'
driver.delete_cookie("test1")
  
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace DeleteCookie {
 class DeleteCookie {
  public static void Main(string[] args) {
   IWebDriver driver = new ChromeDriver();
   try {
    // Navigate to Url
    driver.Navigate().GoToUrl("https://example.com");
    driver.Manage().Cookies.AddCookie(new Cookie("test1", "cookie1"));
    var cookie = new Cookie("test2", "cookie2");
    driver.Manage().Cookies.AddCookie(cookie);

    // delete a cookie with name 'test1'	
    driver.Manage().Cookies.DeleteCookieNamed("test1");

    // Selenium .net bindings also provides a way to delete
    // cookie by passing cookie object of current browsing context
    driver.Manage().Cookies.DeleteCookie(cookie);
   } finally {
    driver.Quit();
   }
  }
 }
}
  
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome

begin
  driver.get 'https://www.example.com'
  driver.manage.add_cookie(name: "test1", value: "cookie1")
  driver.manage.add_cookie(name: "test2", value: "cookie2")

  # delete a cookie with name 'test1'
  driver.manage.delete_cookie('test1')
ensure
  driver.quit
end
  
const {Builder} = require('selenium-webdriver');

(async function deleteCookie() {
  let driver = new Builder()
    .forBrowser('chrome')
    .build();
  try {
    await driver.get('https://www.example.com');
    // Add few cookies
    await driver.manage().addCookie({name: 'test1', value: 'cookie1'});
    await driver.manage().addCookie({name: 'test2', value: 'cookie2'});

    // Delete a cookie with name 'test1'
    await driver.manage().deleteCookie('test1');

    // Get all Available cookies
    await driver.manage().getCookies().then(function (cookies) {
      console.log('cookie details => ', cookies);
    });
    await driver.quit();
  } catch (e){
    console.log(e)
  }
})();

import org.openqa.selenium.Cookie
import org.openqa.selenium.chrome.ChromeDriver

fun main() {
    val driver = ChromeDriver()
    try {
        driver.get("https://example.com")
        driver.manage().addCookie(Cookie("test1", "cookie1"))
        val cookie1 = Cookie("test2", "cookie2")
        driver.manage().addCookie(cookie1)

        // delete a cookie with name 'test1'
        driver.manage().deleteCookieNamed("test1")
        
        // delete cookie by passing cookie object of current browsing context.
        driver.manage().deleteCookie(cookie1)
    } finally {
        driver.quit()
    }
}  
  

删除所有 Cookies

此方法删除当前访问上下文的所有cookie.

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;

public class deleteAllCookies {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        try {
            driver.get("http://www.example.com");
            driver.manage().addCookie(new Cookie("test1", "cookie1"));
            driver.manage().addCookie(new Cookie("test2", "cookie2"));

            // deletes all cookies
            driver.manage().deleteAllCookies();
        } finally {
            driver.quit();
        }
    }
}
  
from selenium import webdriver
driver = webdriver.Chrome()

# Navigate to url
driver.get("http://www.example.com")
driver.add_cookie({"name": "test1", "value": "cookie1"})
driver.add_cookie({"name": "test2", "value": "cookie2"})

#  Deletes all cookies
driver.delete_all_cookies()
  
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace DeleteAllCookies {
 class DeleteAllCookies {
  public static void Main(string[] args) {
   IWebDriver driver = new ChromeDriver();
   try {
    // Navigate to Url
    driver.Navigate().GoToUrl("https://example.com");
    driver.Manage().Cookies.AddCookie(new Cookie("test1", "cookie1"));
    driver.Manage().Cookies.AddCookie(new Cookie("test2", "cookie2"));

    // deletes all cookies
    driver.Manage().Cookies.DeleteAllCookies();
   } finally {
    driver.Quit();
   }
  }
 }
}
  
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome

begin
  driver.get 'https://www.example.com'
  driver.manage.add_cookie(name: "test1", value: "cookie1")
  driver.manage.add_cookie(name: "test2", value: "cookie2")

  # deletes all cookies
  driver.manage.delete_all_cookies
ensure
  driver.quit
end
  
const {Builder} = require('selenium-webdriver');

(async function example() {
  let driver = new Builder()
    .forBrowser('chrome')
    .build();

  try {
    await driver.get('https://www.example.com');
    // Add few cookies
    await driver.manage().addCookie({name: 'test1', value: 'cookie1'});
    await driver.manage().addCookie({name: 'test2', value: 'cookie2'});
    // Delete all cookies
    await driver.manage().deleteAllCookies();
    await driver.quit();
  } catch(e) {
    console.log(e)
  }
})();
import org.openqa.selenium.Cookie
import org.openqa.selenium.chrome.ChromeDriver

fun main() {
    val driver = ChromeDriver()
    try {
        driver.get("https://example.com")
        driver.manage().addCookie(Cookie("test1", "cookie1"))
        driver.manage().addCookie(Cookie("test2", "cookie2"))

        // deletes all cookies
        driver.manage().deleteAllCookies()
    } finally {
        driver.quit()
    }
}
  

Same-Site Cookie属性

此属性允许用户引导浏览器控制cookie, 是否与第三方站点发起的请求一起发送. 引入其是为了防止CSRF(跨站请求伪造)攻击.

Same-Site cookie属性接受以下两种参数作为指令

Strict:

当sameSite属性设置为 Strict, cookie不会与来自第三方网站的请求一起发送.

Lax:

当您将cookie sameSite属性设置为 Lax, cookie将与第三方网站发起的GET请求一起发送.

注意: 到目前为止, 此功能已在Chrome(80+版本), Firefox(79+版本)中提供, 并适用于Selenium 4以及更高版本.

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;

public class cookieTest {
  public static void main(String[] args) {
    WebDriver driver = new ChromeDriver();
    try {
      driver.get("http://www.example.com");
      Cookie cookie = new Cookie.Builder("key", "value").sameSite("Strict").build();
      Cookie cookie1 = new Cookie.Builder("key", "value").sameSite("Lax").build();
      driver.manage().addCookie(cookie);
      driver.manage().addCookie(cookie1);
      System.out.println(cookie.getSameSite());
      System.out.println(cookie1.getSameSite());
    } finally {
      driver.quit();
    }
  }
}
  
from selenium import webdriver

driver = webdriver.Chrome()

driver.get("http://www.example.com")
# Adds the cookie into current browser context with sameSite 'Strict' (or) 'Lax'
driver.add_cookie({"name": "foo", "value": "value", 'sameSite': 'Strict'})
driver.add_cookie({"name": "foo1", "value": "value", 'sameSite': 'Lax'})
cookie1 = driver.get_cookie('foo')
cookie2 = driver.get_cookie('foo1')
print(cookie1)
print(cookie2)
  
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace SameSiteCookie {
  class SameSiteCookie {
    static void Main(string[] args) {
      IWebDriver driver = new ChromeDriver();
      try {
        driver.Navigate().GoToUrl("http://www.example.com");

        var cookie1Dictionary = new System.Collections.Generic.Dictionary<string, object>() {
          { "name", "test1" }, { "value", "cookie1" }, { "sameSite", "Strict" } };
        var cookie1 = Cookie.FromDictionary(cookie1Dictionary);

        var cookie2Dictionary = new System.Collections.Generic.Dictionary<string, object>() {
          { "name", "test2" }, { "value", "cookie2" }, { "sameSite", "Lax" } };
        var cookie2 = Cookie.FromDictionary(cookie2Dictionary);

        driver.Manage().Cookies.AddCookie(cookie1);
        driver.Manage().Cookies.AddCookie(cookie2);

        System.Console.WriteLine(cookie1.SameSite);
        System.Console.WriteLine(cookie2.SameSite);
      } finally {
        driver.Quit();
      }
    }
  }
}
  
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome

begin
  driver.get 'https://www.example.com'
  # Adds the cookie into current browser context with sameSite 'Strict' (or) 'Lax'
  driver.manage.add_cookie(name: "foo", value: "bar", same_site: "Strict")
  driver.manage.add_cookie(name: "foo1", value: "bar", same_site: "Lax")
  puts driver.manage.cookie_named('foo')
  puts driver.manage.cookie_named('foo1')
ensure
  driver.quit
end
  
const {Builder} = require('selenium-webdriver');

(async function sameSiteCookieExample() {
  let driver = new Builder()
    .forBrowser('chrome')
    .build();

  try {
    await driver.get('https://www.example.com');
    // set a cookie on the current domain with sameSite 'Strict' (or) 'Lax'
    await driver.manage().addCookie({name: 'key', value: 'value', sameSite: 'Strict'});
    await driver.manage().addCookie({name: 'key', value: 'value', sameSite: 'Lax'});
    await driver.quit();
  } catch (e) {
    console.log(e);
  }
})();
import org.openqa.selenium.Cookie
import org.openqa.selenium.chrome.ChromeDriver

fun main() {
    val driver = ChromeDriver()
    try {
        driver.get("http://www.example.com")
        val cookie = Cookie.Builder("key", "value").sameSite("Strict").build()
        val cookie1 = Cookie.Builder("key", "value").sameSite("Lax").build()
        driver.manage().addCookie(cookie)
        driver.manage().addCookie(cookie1)
        println(cookie.getSameSite())
        println(cookie1.getSameSite())
    } finally {
        driver.quit()
    }
} 
  

3.4 - 与iFrames和frames一起工作

框架是一种现在已被弃用的方法,用于从同一域中的多个文档构建站点布局。除非你使用的是 HTML5 之前的 webapp,否则你不太可能与他们合作。内嵌框架允许插入来自完全不同领域的文档,并且仍然经常使用。

如果您需要使用框架或 iframe, WebDriver 允许您以相同的方式使用它们。考虑 iframe 中的一个按钮。 如果我们使用浏览器开发工具检查元素,我们可能会看到以下内容:

<div id="modal">
  <iframe id="buttonframe"name="myframe"src="https://seleniumhq.github.io">
   <button>Click here</button>
 </iframe>
</div>

如果不是 iframe,我们可能会使用如下方式点击按钮:

// 这不会工作
driver.findElement(By.tagName("button")).click();
    # 这不会工作
driver.find_element(By.TAG_NAME, 'button').click()
// 这不会工作
driver.FindElement(By.TagName("button")).Click();
    # 这不会工作
driver.find_element(:tag_name,'button').click
// 这不会工作
await driver.findElement(By.css('button')).click();
// 这不会工作
driver.findElement(By.tagName("button")).click()

但是,如果 iframe 之外没有按钮,那么您可能会得到一个 no such element 无此元素 的错误。 这是因为 Selenium 只知道顶层文档中的元素。为了与按钮进行交互,我们需要首先切换到框架, 这与切换窗口的方式类似。WebDriver 提供了三种切换到帧的方法。

使用 WebElement

使用 WebElement 进行切换是最灵活的选择。您可以使用首选的选择器找到框架并切换到它。

// 存储网页元素
WebElement iframe = driver.findElement(By.cssSelector("#modal>iframe"));

// 切换到 frame
driver.switchTo().frame(iframe);

// 现在可以点击按钮
driver.findElement(By.tagName("button")).click();
    # 存储网页元素
iframe = driver.find_element(By.CSS_SELECTOR, "#modal > iframe")

    # 切换到选择的 iframe
driver.switch_to.frame(iframe)

    # 单击按钮
driver.find_element(By.TAG_NAME, 'button').click()
// 存储网页元素
IWebElement iframe = driver.FindElement(By.CssSelector("#modal>iframe"));

// 切换到 frame
driver.SwitchTo().Frame(iframe);

// 现在可以点击按钮
driver.FindElement(By.TagName("button")).Click();
    # Store iframe web element
iframe = driver.find_element(:css,'#modal> iframe')

    # 切换到 frame
driver.switch_to.frame iframe

    # 单击按钮
driver.find_element(:tag_name,'button').click
// 存储网页元素
const iframe = driver.findElement(By.css('#modal> iframe'));

// 切换到 frame
await driver.switchTo().frame(iframe);

// 现在可以点击按钮
await driver.findElement(By.css('button')).click();
// 存储网页元素
val iframe = driver.findElement(By.cssSelector("#modal>iframe"))

// 切换到 frame
driver.switchTo().frame(iframe)

// 现在可以点击按钮
driver.findElement(By.tagName("button")).click()

使用 name 或 id

如果您的 frame 或 iframe 具有 id 或 name 属性,则可以使用该属性。如果名称或 id 在页面上不是唯一的, 那么将切换到找到的第一个。

// 使用 ID
driver.switchTo().frame("buttonframe");

// 或者使用 name 代替
driver.switchTo().frame("myframe");

// 现在可以点击按钮
driver.findElement(By.tagName("button")).click();
    # 通过 id 切换框架
driver.switch_to.frame('buttonframe')

    # 单击按钮
driver.find_element(By.TAG_NAME, 'button').click()
// 使用 ID
driver.SwitchTo().Frame("buttonframe");

// 或者使用 name 代替
driver.SwitchTo().Frame("myframe");

// 现在可以点击按钮
driver.FindElement(By.TagName("button")).Click();
    # Switch by ID
driver.switch_to.frame 'buttonframe'

    # 单击按钮
driver.find_element(:tag_name,'button').click
// 使用 ID
await driver.switchTo().frame('buttonframe');

// 或者使用 name 代替
await driver.switchTo().frame('myframe');

// 现在可以点击按钮
await driver.findElement(By.css('button')).click();
// 使用 ID
driver.switchTo().frame("buttonframe")

// 或者使用 name 代替
driver.switchTo().frame("myframe")

// 现在可以点击按钮
driver.findElement(By.tagName("button")).click()

使用索引

还可以使用frame的索引, 例如可以使用JavaScript中的 window.frames 进行查询.

// 切换到第 2 个框架
driver.switchTo().frame(1);
    # 切换到第 2 个框架
driver.switch_to.frame(1)
// 切换到第 2 个框架
driver.SwitchTo().Frame(1);
    # 基于索引切换到第 2 个 iframe
iframe = driver.find_elements_by_tag_name('iframe')[1]

    # 切换到选择的 iframe
driver.switch_to.frame(iframe)
// 切换到第 2 个框架
await driver.switchTo().frame(1);
// 切换到第 2 个框架
driver.switchTo().frame(1)

离开框架

离开 iframe 或 frameset,切换回默认内容,如下所示:

// 回到顶层
driver.switchTo().defaultContent();
    # 切回到默认内容
driver.switch_to.default_content()
// 回到顶层
driver.SwitchTo().DefaultContent();
    # 回到顶层
driver.switch_to.default_content
// 回到顶层
await driver.switchTo().defaultContent();
// 回到顶层
driver.switchTo().defaultContent()

3.5 - 同窗口和标签一起工作

窗口和标签页

WebDriver 没有区分窗口和标签页。如果你的站点打开了一个新标签页或窗口,Selenium 将允许您使用窗口句柄来处理它。 每个窗口都有一个唯一的标识符,该标识符在单个会话中保持持久性。你可以使用以下方法获得当前窗口的窗口句柄:

driver.getWindowHandle();
driver.current_window_handle
driver.CurrentWindowHandle;
driver.window_handle
await driver.getWindowHandle();
driver.windowHandle

切换窗口或标签页

单击在 <a href=“https://seleniumhq.github.io"target="_blank”>新窗口 中打开链接, 则屏幕会聚焦在新窗口或新标签页上,但 WebDriver 不知道操作系统认为哪个窗口是活动的。 要使用新窗口,您需要切换到它。 如果只有两个选项卡或窗口被打开,并且你知道从哪个窗口开始, 则你可以遍历 WebDriver, 通过排除法可以看到两个窗口或选项卡,然后切换到你需要的窗口或选项卡。

不过,Selenium 4 提供了一个新的 api NewWindow 它创建一个新选项卡 (或) 新窗口并自动切换到它。

// 存储原始窗口的 ID
String originalWindow = driver.getWindowHandle();

// 检查一下,我们还没有打开其他的窗口
assert driver.getWindowHandles().size() == 1;

// 点击在新窗口中打开的链接
driver.findElement(By.linkText("new window")).click();

// 等待新窗口或标签页
wait.until(numberOfWindowsToBe(2));

// 循环执行,直到找到一个新的窗口句柄
for (String windowHandle : driver.getWindowHandles()) {if(!originalWindow.contentEquals(windowHandle)) {driver.switchTo().window(windowHandle);
break;
}
}

// 等待新标签完成加载内容
wait.until(titleIs("Selenium documentation"));
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

    # 启动驱动程序
with webdriver.Firefox() as driver:
    # 打开网址
driver.get("https://seleniumhq.github.io")

    # 设置等待
    wait = WebDriverWait(driver, 10)

    # 存储原始窗口的 ID
    original_window = driver.current_window_handle

    # 检查一下,我们还没有打开其他的窗口
    assert len(driver.window_handles) == 1

    # 单击在新窗口中打开的链接
    driver.find_element(By.LINK_TEXT, "new window").click()

    # 等待新窗口或标签页
    wait.until(EC.number_of_windows_to_be(2))

    # 循环执行,直到找到一个新的窗口句柄
    for window_handle in driver.window_handles:
        if window_handle != original_window:
            driver.switch_to.window(window_handle)
            break

    # 等待新标签页完成加载内容
    wait.until(EC.title_is("SeleniumHQ Browser Automation"))
// 存储原始窗口的 ID
string originalWindow = driver.CurrentWindowHandle;

// 检查一下,我们还没有打开其他的窗口
Assert.AreEqual(driver.WindowHandles.Count, 1);

// 单击在新窗口中打开的链接
driver.FindElement(By.LinkText("new window")).Click();

// 等待新窗口或标签页
wait.Until(wd => wd.WindowHandles.Count == 2);

// 循环执行,直到找到一个新的窗口句柄
foreach(string window in driver.WindowHandles)
{if(originalWindow != window)
{driver.SwitchTo().Window(window);
break;
}
}
// 等待新标签页完成加载内容
wait.Until(wd => wd.Title == "Selenium documentation");
    # 存储原始窗口的 ID
original_window = driver.window_handle

    #检查一下,我们还没有打开其他的窗口
assert(driver.window_handles.length == 1,'Expected one window')

    #点击在新窗口中打开的链接
driver.find_element(link:'new window').click

    #等待新窗口或标签页
wait.until {driver.window_handles.length == 2}

    #循环执行,直到找到一个新的窗口句柄
driver.window_handles.each do |handle|
if handle != original_window
driver.switch_to.window handle
break
end
end

    #等待新标签页完成加载内容
wait.until {driver.title =='Selenium documentation'}
// 存储原始窗口的 ID
const originalWindow = await driver.getWindowHandle();

// 检查一下,我们还没有打开其他的窗口
assert((await driver.getAllWindowHandles()).length === 1);

// 点击在新窗口中打开的链接
await driver.findElement(By.linkText('new window')).click();

// 等待新窗口或标签页
await driver.wait(async () => (await driver.getAllWindowHandles()).length === 2,
10000
);

// 循环执行,直到找到一个新的窗口句柄
const windows = await driver.getAllWindowHandles();
windows.forEach(async handle => {if (handle !== originalWindow) {await driver.switchTo().window(handle);
}
});

// 等待新标签页完成加载内容
await driver.wait(until.titleIs('Selenium documentation'), 10000);
// 存储原始窗口的 ID
val originalWindow = driver.getWindowHandle()

// 检查一下,我们还没有打开其他的窗口
assert(driver.getWindowHandles().size() === 1)

// 点击在新窗口中打开的链接
driver.findElement(By.linkText("new window")).click()

// 等待新窗口或标签页
wait.until(numberOfWindowsToBe(2))

// 循环执行,直到找到一个新的窗口句柄
for (windowHandle in driver.getWindowHandles()) {
if (!originalWindow.contentEquals(windowHandle)) {
driver.switchTo().window(windowHandle)
break
}
}

// 等待新标签页完成加载内容
wait.until(titleIs("Selenium documentation"))

创建新窗口(或)新标签页并且切换

创建一个新窗口 (或) 标签页,屏幕焦点将聚焦在新窗口或标签在上。您不需要切换到新窗口 (或) 标签页。如果除了新窗口之外, 您打开了两个以上的窗口 (或) 标签页,您可以通过遍历 WebDriver 看到两个窗口或选项卡,并切换到非原始窗口。

注意: 该特性适用于 Selenium 4 及其后续版本。

// 打开新标签页并切换到新标签页
driver.switchTo().newWindow(WindowType.TAB);

// 打开一个新窗口并切换到新窗口
driver.switchTo().newWindow(WindowType.WINDOW);
    # 打开新标签页并切换到新标签页
driver.switch_to.new_window('tab')

    # 打开一个新窗口并切换到新窗口
driver.switch_to.new_window('window')
// 打开新标签页并切换到新标签页
driver.SwitchTo().NewWindow(WindowType.Tab)

// 打开一个新窗口并切换到新窗口
driver.SwitchTo().NewWindow(WindowType.Window)
    # 注意:ruby 中的 new_window 只打开一个新标签页(或)窗口,不会自动切换
    # 用户必须切换到新选项卡 (或) 新窗口

    # 打开新标签页并切换到新标签页
driver.manage.new_window(:tab)

    # 打开一个新窗口并切换到新窗口
driver.manage.new_window(:window)
// 打开新标签页并切换到新标签页
await driver.switchTo().newWindow('tab');

// 打开一个新窗口并切换到新窗口
await driver.switchTo().newWindow('window');
// 打开新标签页并切换到新标签页
driver.switchTo().newWindow(WindowType.TAB)

// 打开一个新窗口并切换到新窗口
driver.switchTo().newWindow(WindowType.WINDOW)

关闭窗口或标签页

当你完成了一个窗口或标签页的工作时,_并且_它不是浏览器中最后一个打开的窗口或标签页时,你应该关闭它并切换回你之前使用的窗口。 假设您遵循了前一节中的代码示例,您将把前一个窗口句柄存储在一个变量中。把这些放在一起,你会得到:

//关闭标签页或窗口
driver.close();

//切回到之前的标签页或窗口
driver.switchTo().window(originalWindow);
    #关闭标签页或窗口
driver.close()

    #切回到之前的标签页或窗口
driver.switch_to.window(original_window)
//关闭标签页或窗口
driver.Close();

//切回到之前的标签页或窗口
driver.SwitchTo().Window(originalWindow);
    #关闭标签页或窗口
driver.close

    #切回到之前的标签页或窗口
driver.switch_to.window original_window
//关闭标签页或窗口
await driver.close();

//切回到之前的标签页或窗口
await driver.switchTo().window(originalWindow);
//关闭标签页或窗口
driver.close()

//切回到之前的标签页或窗口
driver.switchTo().window(originalWindow)

如果在关闭一个窗口后忘记切换回另一个窗口句柄,WebDriver 将在当前关闭的页面上执行,并触发一个 No Such Window Exception 无此窗口异常。必须切换回有效的窗口句柄才能继续执行。

在会话结束时退出浏览器

当你完成了浏览器会话,你应该调用 quit 退出,而不是 close 关闭:

driver.quit();
driver.quit()
driver.Quit();
driver.quit
await driver.quit();
driver.quit()

  • 退出将会
    • 关闭所有与 WebDriver 会话相关的窗口和选项卡
    • 结束浏览器进程
    • 结束后台驱动进程
    • 通知 Selenium Grid 浏览器不再使用,以便可以由另一个会话使用它(如果您正在使用 Selenium Grid)

调用 quit() 失败将留下额外的后台进程和端口运行在机器上,这可能在以后导致一些问题。

有的测试框架提供了一些方法和注释,您可以在测试结束时放入 teardown() 方法中。

/**
* 使用 JUnit 的例子
* https://junit.org/junit5/docs/current/api/org/junit/jupiter/api/AfterAll.html
  */
  @AfterAll
  public static void tearDown() {driver.quit();
  }
  
    # unittest teardown
    # https://docs.python.org/3/library/unittest.html?highlight=teardown#unittest.TestCase.tearDown
def tearDown(self):
self.driver.quit()
/*
使用 Visual Studio 的 UnitTesting 的例子
https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.aspx
*/
[TestCleanup]
public void TearDown()
{driver.Quit();
}
    # UnitTest Teardown
    # https://www.rubydoc.info/github/test-unit/test-unit/Test/Unit/TestCase
def teardown
@driver.quit
end
/**
* 使用 Mocha 的例子
* https://mochajs.org/#hooks
  */
  after('Tear down', async function () {await driver.quit();
  });
  
/**
* 使用 JUnit 的例子
* https://junit.org/junit5/docs/current/api/org/junit/jupiter/api/AfterAll.html
  */
  @AfterAll
  fun tearDown() {driver.quit()
  }
  

如果不在测试上下文中运行 WebDriver,您可以考虑使用 try / finally,这是大多数语言都提供的, 这样一个异常处理仍然可以清理 WebDriver 会话。

try {//WebDriver 代码…} finally {driver.quit();
}
try:
    #WebDriver 代码…
finally:
driver.quit()
try {//WebDriver 代码…} finally {driver.Quit();
}
begin
    #WebDriver 代码…
ensure
driver.quit
end
try {//WebDriver 代码…} finally {await driver.quit();
}
try {//WebDriver 代码…} finally {driver.quit()
}

Python 的 WebDriver 现在支持 Python 上下文管理器,当使用 with 关键字时,可以在执行结束时自动退出驱动程序。

with webdriver.Firefox() as driver:
  # WebDriver 代码…

# 在此缩进位置后 WebDriver 会自动退出

窗口管理

屏幕分辨率会影响 web 应用程序的呈现方式,因此 WebDriver 提供了移动和调整浏览器窗口大小的机制。

获取窗口大小

获取浏览器窗口的大小(以像素为单位)。

// 分别获取每个尺寸
int width = driver.manage().window().getSize().getWidth();
int height = driver.manage().window().getSize().getHeight();

// 或者存储尺寸并在以后查询它们
Dimension size = driver.manage().window().getSize();
int width1 = size.getWidth();
int height1 = size.getHeight();
    # 分别获取每个尺寸
width = driver.get_window_size().get("width")
height = driver.get_window_size().get("height")

    # 或者存储尺寸并在以后查询它们
size = driver.get_window_size()
width1 = size.get("width")
height1 = size.get("height")
// 分别获取每个尺寸
int width = driver.Manage().Window.Size.Width;
int height = driver.Manage().Window.Size.Height;

// 或者存储尺寸并在以后查询它们
System.Drawing.Size size = driver.Manage().Window.Size;
int width1 = size.Width;
int height1 = size.Height;
    # 分别获取每个尺寸
width = driver.manage.window.size.width
height = driver.manage.window.size.height

    # 或者存储尺寸并在以后查询它们
size = driver.manage.window.size
width1 = size.width
height1 = size.height
// 分别获取每个尺寸
const {width, height} = await driver.manage().window().getRect();

// 或者存储尺寸并在以后查询它们
const rect = await driver.manage().window().getRect();
const width1 = rect.width;
const height1 = rect.height;
// 分别获取每个尺寸
val width = driver.manage().window().size.width
val height = driver.manage().window().size.height

// 或者存储尺寸并在以后查询它们
val size = driver.manage().window().size
val width1 = size.width
val height1 = size.height

设置窗口大小

恢复窗口并设置窗口大小。

driver.manage().window().setSize(new Dimension(1024, 768));
driver.set_window_size(1024, 768)
driver.Manage().Window.Size = new Size(1024, 768);
driver.manage.window.resize_to(1024,768)
await driver.manage().window().setRect({width: 1024, height: 768});
driver.manage().window().size = Dimension(1024, 768)

得到窗口的位置

获取浏览器窗口左上角的坐标。

// 分别获取每个尺寸
int x = driver.manage().window().getPosition().getX();
int y = driver.manage().window().getPosition().getY();

// 或者存储尺寸并在以后查询它们
Point position = driver.manage().window().getPosition();
int x1 = position.getX();
int y1 = position.getY();
    # 分别获取每个尺寸
x = driver.get_window_position().get('x')
y = driver.get_window_position().get('y')

    # 或者存储尺寸并在以后查询它们
position = driver.get_window_position()
x1 = position.get('x')
y1 = position.get('y')
// 分别获取每个尺寸
int x = driver.Manage().Window.Position.X;
int y = driver.Manage().Window.Position.Y;

// 或者存储尺寸并在以后查询它们
Point position = driver.Manage().Window.Position;
int x1 = position.X;
int y1 = position.Y;
    #Access each dimension individually
x = driver.manage.window.position.x
y = driver.manage.window.position.y

    # Or store the dimensions and query them later
rect  = driver.manage.window.rect
x1 = rect.x
y1 = rect.y
// 分别获取每个尺寸
const {x, y} = await driver.manage().window().getRect();

// 或者存储尺寸并在以后查询它们
const rect = await driver.manage().window().getRect();
const x1 = rect.x;
const y1 = rect.y;
// 分别获取每个尺寸
val x = driver.manage().window().position.x
val y = driver.manage().window().position.y

// 或者存储尺寸并在以后查询它们
val position = driver.manage().window().position
val x1 = position.x
val y1 = position.y

设置窗口位置

将窗口移动到设定的位置。

// 将窗口移动到主显示器的左上角
driver.manage().window().setPosition(new Point(0, 0));
    # 将窗口移动到主显示器的左上角
driver.set_window_position(0, 0)
// 将窗口移动到主显示器的左上角
driver.Manage().Window.Position = new Point(0, 0);
driver.manage.window.move_to(0,0)
// 将窗口移动到主显示器的左上角
await driver.manage().window().setRect({x: 0, y: 0});
// 将窗口移动到主显示器的左上角
driver.manage().window().position = Point(0,0)

最大化窗口

扩大窗口。对于大多数操作系统,窗口将填满屏幕,而不会阻挡操作系统自己的菜单和工具栏。

driver.manage().window().maximize();
driver.maximize_window()
driver.Manage().Window.Maximize();
driver.manage.window.maximize
await driver.manage().window().maximize();
driver.manage().window().maximize()

最小化窗口

最小化当前浏览上下文的窗口. 这种命令的精准行为将作用于各个特定的窗口管理器.

最小化窗口通常将窗口隐藏在系统托盘中.

注意: 此功能适用于Selenium 4以及更高版本.

driver.manage().window().minimize();
driver.minimize_window()
driver.Manage().Window.Minimize();
driver.manage.window.minimize
await driver.manage().window().minimize();
driver.manage().window().minimize()

全屏窗口

填充整个屏幕,类似于在大多数浏览器中按下 F11。

driver.manage().window().fullscreen();
driver.fullscreen_window()
driver.Manage().Window.FullScreen();
driver.manage.window.full_screen
await driver.manage().window().fullscreen();
driver.manage().window().fullscreen()

屏幕截图

用于捕获当前浏览上下文的屏幕截图. WebDriver端点 屏幕截图 返回以Base64格式编码的屏幕截图.

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.chrome.ChromeDriver;
import java.io.*;
import org.openqa.selenium.*;

public class SeleniumTakeScreenshot {
public static void main(String args[]) throws IOException {
WebDriver driver = new ChromeDriver();
driver.get("http://www.example.com");
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File("./image.png"));
driver.quit();
}
}
from selenium import webdriver

driver = webdriver.Chrome()

    # Navigate to url
driver.get("http://www.example.com")

    # Returns and base64 encoded string into image
driver.save_screenshot('./image.png')

driver.quit()
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;

    var driver = new ChromeDriver();
    driver.Navigate().GoToUrl("http://www.example.com");
    Screenshot screenshot = (driver as ITakesScreenshot).GetScreenshot();
    screenshot.SaveAsFile("screenshot.png", ScreenshotImageFormat.Png); // Format values are Bmp, Gif, Jpeg, Png, Tiff
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome

begin
driver.get 'https://example.com/'

    # Takes and Stores the screenshot in specified path
driver.save_screenshot('./image.png')

end
let {Builder} = require('selenium-webdriver');
let fs = require('fs');

(async function example() {
let driver = await new Builder()
.forBrowser('chrome')
.build();

    await driver.get('https://www.example.com');
    // Returns base64 encoded string
    let encodedString = await driver.takeScreenshot();
    await fs.writeFileSync('./image.png', encodedString, 'base64');
    await driver.quit();
}())
import com.oracle.tools.packager.IOUtils.copyFile
import org.openqa.selenium.*
import org.openqa.selenium.chrome.ChromeDriver
import java.io.File

fun main(){
val driver =  ChromeDriver()
driver.get("https://www.example.com")
val scrFile = (driver as TakesScreenshot).getScreenshotAs<File>(OutputType.FILE)
copyFile(scrFile, File("./image.png"))
driver.quit()
}

元素屏幕截图

用于捕获当前浏览上下文的元素的屏幕截图. WebDriver端点 屏幕截图 返回以Base64格式编码的屏幕截图.

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import java.io.File;
import java.io.IOException;

public class SeleniumelementTakeScreenshot {
public static void main(String args[]) throws IOException {
WebDriver driver = new ChromeDriver();
driver.get("https://www.example.com");
WebElement element = driver.findElement(By.cssSelector("h1"));
File scrFile = element.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File("./image.png"));
driver.quit();
}
}
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()

    # Navigate to url
driver.get("http://www.example.com")

ele = driver.find_element(By.CSS_SELECTOR, 'h1')

    # Returns and base64 encoded string into image
ele.screenshot('./image.png')

driver.quit()
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;

    // Webdriver
    var driver = new ChromeDriver();
    driver.Navigate().GoToUrl("http://www.example.com");

    // Fetch element using FindElement
    var webElement = driver.FindElement(By.CssSelector("h1"));

    // Screenshot for the element
    var elementScreenshot = (webElement as ITakesScreenshot).GetScreenshot();
    elementScreenshot.SaveAsFile("screenshot_of_element.png");
    # Works with Selenium4-alpha7 Ruby bindings and above
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome

begin
driver.get 'https://example.com/'
ele = driver.find_element(:css, 'h1')

    # Takes and Stores the element screenshot in specified path
ele.save_screenshot('./image.jpg')
end
const {Builder, By} = require('selenium-webdriver');
let fs = require('fs');

(async function example() {
let driver = await new Builder()
.forBrowser('chrome')
.build();

await driver.get('https://www.example.com');
let ele = await driver.findElement(By.css("h1"));
// Captures the element screenshot
let encodedString = await ele.takeScreenshot(true);
await fs.writeFileSync('./image.png', encodedString, 'base64');
await driver.quit();
}())
import org.apache.commons.io.FileUtils
import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.*
import java.io.File

fun main() {
val driver = ChromeDriver()
driver.get("https://www.example.com")
val element = driver.findElement(By.cssSelector("h1"))
val scrFile: File = element.getScreenshotAs(OutputType.FILE)
FileUtils.copyFile(scrFile, File("./image.png"))
driver.quit()
}

执行脚本

在当前frame或者窗口的上下文中,执行JavaScript代码片段.