在 IntelliJ IDEA 中使用 Java 和 Selenium 模拟 Chrome 浏览器教程
1. 前言
Selenium 是一个流行的自动化测试工具,支持多种浏览器平台。它的灵活性和丰富的功能使其非常适合测试各种类型的网页应用。虽然关于 Selenium 和 Java 的资料较少且分散,但 Java 爬虫其实非常方便,只要多看源码就能掌握。
2. 环境准备
在开始之前,请确保已安装以下工具,并注意 Chrome 版本必须与 ChromeDriver 版本一致。
-
Java 开发环境: JDK 1.8, Maven 3+, IntelliJ IDEA
-
ChromeDriver:ChromeDriver 下载
-
历史版本 Chrome:历史版本 Chrome 下载
3. 关闭谷歌自动更新
通过服务禁用更新服务
- 按下
Win+R
键,输入services.msc
并确定。 - 在服务窗口中,找到并双击打开两个 Google 更新服务。
- 在服务属性窗口中,点击
停止
,在启动类型
中选择禁用
并确定。 - 根据谷歌浏览器的安装路径(通常是
C:\Program Files (x86)\Google
或C:\Program Files\Google
)找到谷歌目录,右键点击Update
更新文件夹,在常规
栏点击启动类型为禁用
并确定。
通过任务计划程序禁用更新任务
- 右键点击
我的电脑
,选择管理
。 - 在对话框中选择
任务计划程序
。 - 在任务计划程序库中找到两个与 Chrome 自动更新相关的任务计划,如
GoogleUpdateTaskMachineCore
和GoogleUpdateTaskMachineUA
,右键选择禁用。
4. 项目添加 Maven 依赖项
在项目的 pom.xml
文件中,添加 Selenium 和 WebDriverManager 的依赖项:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zhouquan</groupId>
<artifactId>file-upload</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>file-upload</name>
<description>selenium模拟</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.core5</groupId>
<artifactId>httpcore5</artifactId>
<version>5.2</version>
</dependency>
</dependencies>
</project>
添加依赖项后,点击 IntelliJ IDEA 界面右上角的 Maven
面板中的 Reload
按钮,重新加载 Maven 项目以确保依赖项正确导入。
5. 编写自动化脚本
在 src/main/java/com/example
目录下创建一个名为 App.java
的文件,并编写以下代码:
package com.example;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
public class App {
public static void main(String[] args) {
// 使用 WebDriverManager 设置 ChromeDriver
WebDriverManager.chromedriver().setup();
// 创建一个新的 ChromeDriver 实例
WebDriver driver = new ChromeDriver();
try {
// 打开目标网站
driver.get("https://www.example.com");
// 查找要点击的元素,例如通过 id, class, 或者其他选择器
WebElement elementToClick = driver.findElement(By.id("button-id"));
// 执行点击操作
elementToClick.click();
// 其他操作(如验证结果、截图等)
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭浏览器
//driver.quit();
}
}
}
6. 项目运行效果
运行上述代码后,浏览器会自动打开并执行相应的操作。确认所有步骤正确完成,自动化脚本会顺利运行并执行预定的测试任务。
7. 代码示例
package com.reptile;
import com.file.ReadWriteFileUtils;
import lombok.SneakyThrows;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* ChromeDriver工具类,提供多种初始化和操作方法
*
* @Author: zhouquan
* @Date: 2024/6/23
* @Version: 1.0
* @Description: ChromeDriver工具类,提供多种初始化和操作方法
*/
public class ChromeDriverUtil {
// 文件版本, 防止多线程缓存文件和用户文件共享, 导致创建错误
private static AtomicInteger fileSerial = new AtomicInteger(0);
private ChromeDriver driver;
/**
* 构造函数,初始化ChromeDriver
* @param path ChromeDriver路径
* @param pd 是否显示浏览器
* @param img 是否加载图片
*/
public ChromeDriverUtil(String path, boolean pd, boolean img) {
init(path, pd, img);
}
@SneakyThrows
private void init(String path, boolean pd, boolean img) {
// 设置ChromeDriver路径
System.setProperty("webdriver.chrome.driver", path);
ChromeOptions options = new ChromeOptions();
if (!pd) {
options.addArguments("--headless"); // 无浏览器模式
}
// 优化参数设置
options.addArguments("--disable-gpu"); // 禁用GPU
options.addArguments("--disable-software-rasterizer"); // 禁用3D软件光栅化器
options.addArguments("--no-sandbox"); // 允许Linux root用户执行
options.addArguments("--disable-dev-shm-usage"); // 解决某些VM环境中Chrome崩溃问题
if (img) {
options.addArguments("blink-settings=imagesEnabled=false"); // 禁止加载图片
options.addArguments("--disable-images");
}
// 设置临时文件夹
String tmpdir = System.getProperty("java.io.tmpdir");
String dir = tmpdir + File.separator + "chrome_file_data_cache" + File.separator + fileSerial.incrementAndGet();
File dataDir = new File(dir + File.separator + "data");
if (!dataDir.exists()) {
dataDir.mkdirs();
}
File cacheDir = new File(dir + File.separator + "cache");
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
options.addArguments("--user-data-dir=" + dataDir.getAbsolutePath()); // 设置用户数据目录
options.addArguments("--disk-cache-dir=" + cacheDir.getAbsolutePath()); // 设置缓存目录
options.addArguments("--incognito"); // 无痕模式
options.addArguments("--disable-plugins"); // 禁用插件
options.addArguments("--disable-extensions"); // 禁用扩展
options.addArguments("--disable-popup-blocking"); // 关闭弹窗拦截
options.addArguments("--ignore-certificate-errors"); // 忽略证书错误
options.addArguments("--allow-running-insecure-content"); // 允许加载不安全内容
options.addArguments("--disable-infobars"); // 禁用浏览器正在被自动化程序控制的提示
if (!pd) {
// 无浏览器模式-最大化窗口,防止有些元素被隐藏
int screenWidth = ((int) java.awt.Toolkit.getDefaultToolkit().getScreenSize().width);
int screenHeight = ((int) java.awt.Toolkit.getDefaultToolkit().getScreenSize().height);
options.addArguments("window-size=" + screenWidth + "," + screenHeight);
}
// 随机设置请求头
options.addArguments("--user-agent=" + UserAgent.getUserAgentWindows());
proxy(options, false); // 设置代理,true 开启代理
driver = new ChromeDriver(options); // 实例化ChromeDriver
if (pd) {
driver.manage().window().maximize(); // 显示模式下最大化窗口,防止有些元素被隐藏
}
// 设置隐式等待
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
}
// 无头模式,不加载图片
public static ChromeDriverUtil buildHide(String path) {
return new ChromeDriverUtil(path, false, true);
}
// 无头模式,加载图片
public static ChromeDriverUtil buildHideImg(String path) {
return new ChromeDriverUtil(path, false, false);
}
// 显示浏览器,全功能
public static ChromeDriverUtil build(String path) {
return new ChromeDriverUtil(path, true, false);
}
public ChromeDriver getDriver() {
return driver;
}
// 强制等待,代码在执行到某个位置时强制等待一段时间
@SneakyThrows
public void sleep(long ms) {
Thread.sleep(ms);
}
// 显示等待,为了解决隐式等待遗留的问题
public WebElement wait(int seconds, ExpectedCondition<WebElement> expectedCondition) {
WebDriverWait webDriverWait = new WebDriverWait(driver, seconds);
WebElement until = webDriverWait.until(expectedCondition);
return until;
}
// 设置代理
private void proxy(ChromeOptions options, boolean pd) {
if (pd) {
String prox = "127.0.0.1:" + 8080; // 代理地址
Proxy p = new Proxy();
p.setHttpProxy(prox); // 设置HTTP代理
options.setProxy(p);
}
}
// 截图
public void screenshotPNG(TakesScreenshot takesScreenshot, File file) {
byte[] screenshotAs = takesScreenshot.getScreenshotAs(OutputType.BYTES);
ReadWriteFileUtils.writeByte(screenshotAs, file);
try (FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
bos.write(screenshotAs, 0, screenshotAs.length); // 写入数据
} catch (Exception e) {
e.printStackTrace();
}
}
}
8.常用方法示例
页面请求
// 请求一个页面,不支持前进和后退切换
driver.get(url);
// 类似get,支持前进和后退切换
driver.navigate().to(url);
// 退到上一个页面,前提是必须前进了一个页面才能回退
driver.navigate().back();
// 指前进到下一个页面,前提是必须后退后才能前进
driver.navigate().forward();
// 刷新当前页面
driver.navigate().refresh();
定位标签
// 通用搜索,第一个,By里包含常用的各种搜索
WebElement findElement(By by);
// 通用搜索,多个,By里包含常用的各种搜索
List<WebElement> findElements(By by);
// 查询指定id的标签
WebElement findElementById(String using);
// 查询a标签内容是using的,第一个
WebElement findElementByLinkText(String using);
// 查询a标签内容是using的,多个
List<WebElement> findElementsByLinkText(String using);
// 查询a标签内容是using的,模糊匹配,第一个
WebElement findElementByPartialLinkText(String using);
// 查询a标签内容是using的,模糊匹配,多个
List<WebElement> findElementsByPartialLinkText(String using);
// 查询标签名称,第一个
WebElement findElementByTagName(String using);
// 查询标签名称,多个
List<WebElement> findElementsByTagName(String using);
// 查询标签属性name,第一个
WebElement findElementByName(String using);
// 查询标签属性name,多个
List<WebElement> findElementsByName(String using);
// 查询标签数据class,第一个
WebElement findElementByClassName(String using);
// 查询标签数据class,多个
List<WebElement> findElementsByClassName(String using);
// 使用css选择器,第一个
WebElement findElementByCssSelector(String using);
// 使用css选择器,多个
List<WebElement> findElementsByCssSelector(String using);
// 使用XPath选择器,第一个
WebElement findElementByXPath(String using);
// 使用XPath选择器,多个
List<WebElement> findElementsByXPath(String using);
获取内容
// 获取页面html
String getPageSource();
// 获取页面标题
String getTitle();
// 获取此元素(包括子元素)的可见(即未被CSS隐藏)文本
String getText();
// 获取此元素的标签名
String getTagName();
// 获取元素指定属性的值
String getAttribute(String name);
// 获取当前元素,基于样式的计算属性值
String getCssValue(String propertyName);
// 获取元素的尺寸及其在视口中的位置
Rectangle getRect();
操作元素
// 输入文本
void sendKeys(CharSequence... keysToSend);
// 清空文本
void clear();
// 点击元素
void click();
// 提交表单
void submit();
// 模拟鼠标移动到元素并点击
Actions actions = new Actions(driver);
actions.moveToElement(element).click().perform();
// 执行JavaScript代码
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.scrollTo(0, document.body.scrollHeight)"); // 滚动到底部
显式和隐式等待
// 显式等待
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("someId")));
// 隐式等待
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
切换窗口和框架
// 切换到指定窗口
driver.switchTo().window(windowHandle);
// 切换到指定框架
driver.switchTo().frame(frameNameOrId);
// 切换到父框架
driver.switchTo().parentFrame();
// 切换到默认内容
driver.switchTo().defaultContent();
截图并保存为文件
// 截图并保存为文件
File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile, new File("/path/to/screenshot.png"));
关闭和退出
// 关闭当前窗口
driver.close();
// 关闭所有窗口并退出
driver.quit();
文件操作工具类示例
package com.file;
import java.io.*;
public class ReadWriteFileUtils {
// 写入字节数组到文件
public static void writeByte(byte[] data, File file) {
try (FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
bos.write(data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
}
}
// 从文件读取字节数组
public static byte[] readByte(File file) {
byte[] data = null;
try (FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis)) {
data = new byte[(int) file.length()];
bis.read(data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
}
代理配置工具类示例
package com.proxy;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.chrome.ChromeOptions;
public class ProxyUtils {
// 设置代理
public static void setProxy(ChromeOptions options, boolean enableProxy) {
if (enableProxy) {
String proxyAddress = "101.200.127.149:3129";
Proxy proxy = new Proxy();
proxy.setHttpProxy(proxyAddress);
options.setProxy(proxy);
}
}
}
随机用户代理工具类示例
package com.useragent;
import java.util.Random;
public class UserAgent {
public static String getUserAgentWindows() {
String[] userAgents = {
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0"
};
Random random = new Random();
return userAgents[random.nextInt(userAgents.length)];
}
}
使用示例
public class Main {
public static void main(String[] args) {
// 初始化无头模式,禁用图片加载
ChromeDriverUtil driverUtil = ChromeDriverUtil.buildHide("path/to/chromedriver");
// 访问页面
driverUtil.getDriver().get("https://www.example.com");
// 定位元素
WebElement element = driverUtil.getDriver().findElement(By.id("elementId"));
// 获取元素文本
String text = element.getText();
System.out.println("Element text: " + text);
// 截图
driverUtil.screenshotPNG((TakesScreenshot) driverUtil.getDriver(), new File("screenshot.png"));
// 关闭浏览器
driverUtil.getDriver().quit();
}
}
9. 总结
本文介绍如何在 IntelliJ IDEA 中使用 Selenium 和 ChromeDriver 进行网页爬取和自动化操作,包括以下几个方面:
- 环境准备:配置 Java 开发环境、下载并安装 ChromeDriver、设置 Chrome 浏览器和 ChromeDriver 版本一致、禁用 Chrome 自动更新
- 添加 Maven 依赖项:在项目的
pom.xml
文件中添加 Selenium 和 WebDriverManager 依赖项 - 编写自动化脚本:创建
App.java
文件,编写基本的 Selenium 自动化脚本,演示如何打开网页并进行基本操作 - ChromeDriver 工具类:提供
ChromeDriverUtil
工具类,包含初始化 ChromeDriver、代理配置、等待、截图等功能 - 常用方法:列出 Selenium 中常用的方法,包括请求、定位标签、获取内容、操作元素、等待、切换窗口和框架、截图、关闭和退出
- 文件操作工具类:提供
ReadWriteFileUtils
工具类,用于文件读写操作 - 代理配置工具类:提供
ProxyUtils
工具类,用于设置代理 - 随机用户代理工具类:提供
UserAgent
工具类,用于随机生成用户代理字符串 - 使用示例:提供完整的使用示例,演示如何使用
ChromeDriverUtil
进行网页爬取和自动化操作