Selenium4 + Java Web自动化测试入门指南:从环境搭建到常用操作详解

Java Web 自动化

一、QuickStart

1.1 Selenium 和 WebDriverManager

Selenium 是我们常用来进行 Web 自动化测试的第三方库,Python 也支持使用 Selenium,支持 Chrome、Edge、Safari、Firefox 这些主流浏览器;WebDriverManager 是用来自动识别浏览器及其版本并下载对应驱动。

导入 Selenium

Java 复制代码
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>4.23.0</version>
</dependency>

导入 WebDriverManager

Java 复制代码
<dependency>
    <groupId>io.github.bonigarcia</groupId>
    <artifactId>webdrivermanager</artifactId>
    <version>5.8.0</version>
    <scope>test</scope>
</dependency>

1.2 操作步骤

Java 复制代码
public void firstTest(){
    *//浏览器驱动自动化*
    WebDriverManager.chromedriver().setup();
    ChromeOptions chromeOptions = new ChromeOptions();
    
    *//浏览器允许所有驱动路径*
    chromeOptions.addArguments("--remote-allow-origins=*");

    *//打开浏览器*
    WebDriver driver = new ChromeDriver(chromeOptions);

    *//跳转到百度首页*
    driver.get("https://www.baidu.com");

    *//通过 ID 找到输入框,并输入文字*
    driver.findElement(By.id("chat-textarea")).sendKeys("蔡徐坤");

    *//通过 ID 找到提交按钮,并点击*
    driver.findElement(By.id("chat-submit-button")).click();
    driver.quit();
}

直接使用这种脚本,访问一个网站次数较多,很容易触发反爬机制,因为实际上我们实现 Web UI 测试自动化的技术直接更改写法就是写爬虫。出于练习自动化脚本的目的,而不是专门写爬虫,可以增加以下配置来伪装真人操作

Java 复制代码
chromeOptions.addArguments("--disable-blink-features=AutomationControlled");
chromeOptions.setExperimentalOption("excludeSwitches", new String[]{"enable-automation"});
chromeOptions.setExperimentalOption("useAutomationExtension", false);

driver.executeScript("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})");

二、常用函数

Selenium 支持很多种选择方式,但是用的比较多的只有两种 cssSelectorxpath,而且前者更多

无论哪种方式,在浏览器的开发者工具中都可以直接 copy 页面控件的相应元素,

2.1 FindElement

FindElement 用来选择页面上的某个空间进行互动

2.1.1 选择方式

2.1.1.1 cssSelector

直接通过在样式表中的选择方式选择即可,比如 <input id="name" value="UseName">,可以通过下面的方式选中

Java 复制代码
*chromeDriver.findElement(By.cssSelector("#chat-textarea")).sendKeys("徐大虾");*
2.1.1.2 xpath

Xpath 相对规则多一些,有如下几条:

  1. //* 表示页面下的所有元素

  2. / 选择一个空间下的子元素

  3. /... 选择一个界面下的某些元素,比如 /input 获取到的就是当前页面下的所有 input 标签

  4. /[@...] 选择具有某种属性的所有元素,比如 //*[@id="chat-textarea"] 获取到的是当前页面 id 为 chat-textarea 的元素

  5. .. 当前元素父元素

  6. /div[3] 通过下标的方式获取同一层级中的元素中的一个,比如百度主页中的热搜内容条,都在同一层级,其中某一条通过 xpath 的方式选择就可以通过这种方式

Java 复制代码
**List**<**WebElement**> rets = chromeDriver.findElements(**By**.xpath("//*[@id=\"hotsearch-content-wrapper\"]/li/a/span[2]"));
**if**(rets.size() != 0){
    **for**(**WebElement** e: rets){
        **System**.out.println(e.getText());
    }
}

如上获取百度(https://www.baidu.com)的热搜内容。

2.1.2 互动行为

click

模拟用户对空间的点击行为,可以操作 button a 等,但是并不是"万物可点击",click 无法操作不可见、不存在的控件

sendKeys

模拟键盘输入,对于控件的输入是叠加行为,可以直接通过字符串的方式传入内容

clear

情况输入内容

getText/getAttribute

FindElement/FindElements 返回的控件的类型是 WebElement。

前者用来获取标签的文本内容,后者用来获取标签某个属性的值,比如:

HTML 复制代码
<button>百度一下</button>
<button value="百度一下"><button>

前者文字内容的获取就可以通过 getText,但是后者就需要通过 getAttribute("value") 的方式

2.2 window 句柄

windows句柄是抽象出来的用来标识一个标签页的字符串,通过 getWindowHandle 获取当前标签页句柄,getWindowHandles 获取所有标签页的句柄

为什么会使用到这个句柄? 例如在发生页面跳转的时候,有的就是直接在当前标签页展示,还有的是跳转到新的标签页进行展示。对于后者,我们的操作依然停留在旧的标签页,也就是说我们无法操作新的标签页,例如

Java 复制代码
driver.findElement(**By**.cssSelector("#chat-textarea")).sendKeys("徐大虾");
driver.findElement(**By**.cssSelector("#chat-submit-button")).click();

//这样写是有问题的,后面进行解释

driver.findElement(**By**.cssSelector("#\\31  > div > h3 > a")).click();

这几句代码模拟了在百度首页输入,点击"百度一下",再点击第一个搜索结果的行为。此时信息展示页是在一个新的标签,如果继续直接操作的话,那么都是在老的标签页进行的

可以通过这种方式进行页面的切换:

Java 复制代码
**Set**<**String**> handles = driver.getWindowHandles();
**for**(**String** handle: handles){
    **if**(!handle.equals(driver.getWindowHandle())){
        driver.switchTo().window(handle);
    }
}

那么多个标签页呢?在 Web 自动化测试的场景下,基本最多两个标签页,更多就可以使用 driver.get("url") 的方式直接跳转

2.3 窗口操作

Java 复制代码
driver.manage.window().fullscreen(); //全屏
driver.manage.window().minimize(); //最小化
driver.manage.window().maximize(); //最大化

2.4 屏幕截图

Java 复制代码
File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile, new File("test_screenshot.png"));

通过这种方式需要手动指定不同的截图名,否则会覆盖。同时为了日后整理方便,建议通过时间戳操作将截图文件通过类似 年月日/时分秒.png 的方式存储,其中 FileUtils 需要额外导包

Java 复制代码
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

2.5 等待

脚本执行中未找到元素抛出异常,可能是什么原因?

  • xpath、css 从浏览器中拷贝错误

  • xpath、css 和选择器种类搭配错误

  • 动态标签

  • 自动化页面和手动操作页面不同

  • 页面加载完成前代码就已经执行完导致找不到元素

2.5.1 Thread.sleep

因为时间是死的,所以可能要么太长,要么太短

2.5.2 隐式等待

隐式等待的等待对象是全局所有元素,当所有元素加载完成后 findElement/findElements 会正常执行;当到达超时时间会抛出异常(隐式等待的等待效果只作用于控件选择)

Java 复制代码
*driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));*

2.5.3 显式等待(智能等待)

显式等待,等待的控件可以自己手动指定,并且等待结束的条件同样可以自己指定。

相比隐式等待,写法更麻烦,但是可以不等待不需要的元素,并且等待行为更灵活,比如 presenceOfElementLocated 元素加载完成、elementToBeClickable 元素可点击(可见、未遮挡)

Java 复制代码
WebDriverWait webDriverWait = new WebDriverWait(driver, Duration.ofSeconds(3));*//显示等待(智能等待)*
webDriverWait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#\\31  > div > h3 > a")));

2.6 标签页操作

向前跳转

Java 复制代码
driver.navigate().forward();

向后跳转

Java 复制代码
driver.navigate().back();

刷新

Java 复制代码
driver.navigate().refresh();

2.7 弹窗处理

首先要明白弹窗(指的是浏览器弹窗而不是网页弹窗,比如 alert)是一种警告、异常一类的存在,有弹窗时是无法选择页内标签或者进行其他操作的

  1. 切换到 alert 弹窗上进行操作

    Java 复制代码
    Alert alert = driver.switchTo.alert();
  2. 弹窗操作,如果只有一个按钮,那么 accept 和 dismiss 达成的行为是一样的:点击唯一的按钮

    Java 复制代码
    alert.accept(); //点击确认按钮
    alert.dismiss(); // 点击取消按钮
    alert.sendKeys(); // 如果弹窗中有输入框,进行输入

2.8 无头模式

所谓无头模式,就是整个脚本和浏览器相应都在后台进行,只有运行终端会进行相应输出。

建议使用 options.addArgument("--headless=new"),或者也可以使用 options.addArgument("--headless")

但是使用无头模式更容易被反爬机制识别

2.9 PageLoadStrategy

页加载策略是每个标签页跳转后对页面元素的等待策略,默认是 NORMAL

  • NORMAL 等待所有 DOM 解析完毕,图片、css、视频、js 加载完成后,才从阻塞中继续往下执行

  • EAGER 等待 DOM 解析完毕,不等待图片、视频、js、css。但实际上现代很多页面结构中的标签在源代码中是不存在的,比如 Vue 中一些标签就是通过 js 渲染的。如果确定是源代码中的控件,不依赖 js 代码生成可以直接使用这个页加载策略,否则建议搭配显式等待

  • None 不进行任何等待,直接完成页加载的过程

之所以要设置页加载策略,是因为我们的隐式等待、显式等待都会等待页加载完成。对于显式加载而言,即使所需空间符合等待条件了,也要等待页加载完成

3.0 关闭

  • 关闭页面,driver.close(),这种方式关闭的是当前标签页

  • 关闭浏览器,driver.quit(),退出浏览器,销毁浏览器句柄

相关推荐
Awna2 小时前
Golang 大小写可见性规范
开发语言·后端·golang
孙启超2 小时前
【AI应用开发】LangChain 中 Chain 和 Agent 核心区别?
java·人工智能·langchain·llm·rag·ai应用开发·agent loop
J船长2 小时前
Spec Kit 入门:AI Agent 时代的规格驱动开发实践
前端
leoZ2313 小时前
实战复盘:用 Claude Code 从零搭一个 GitHub PR 统计工具
java·人工智能·python·深度学习·自然语言处理·github·llama
William Dawson3 小时前
【踩坑实录|Hive1\.2\.1数据服务接口5大疑难问题调试与全方位优化方案】
java·hive·spring boot
2601_955759883 小时前
如何识别 Claude API 低价值调用并优化
java
AI科技星3 小时前
曲率‑挠率与 $\boldsymbol{\omega/c}$ 的关系、精算验证及其物理意义
c语言·开发语言·线性代数·算法·决策树·机器学习·ai科技星
程序员黑豆3 小时前
鸿蒙应用开发 @Builder 使用教程:从入门到精通
前端·harmonyos
CCYe、3 小时前
限流与配额:企业AI网关的工程实践
前端·人工智能