Chromium / ChromeDriver 完全指南 / 03 - Selenium 集成
03 - Selenium 集成
使用 Selenium WebDriver 控制 Chrome/Chromium,理解 WebDriver 协议工作原理,掌握浏览器启动与选项配置。
3.1 Selenium 简介
Selenium 是最成熟的浏览器自动化框架,始于 2004 年,目前由 W3C 标准化为 WebDriver 协议。
Selenium 版本演进
| 版本 | 年份 | 关键变化 |
|---|---|---|
| Selenium 1 (RC) | 2004 | 通过 JS 注入控制浏览器,需启动 Selenium Server |
| Selenium 2 (WebDriver) | 2011 | 引入 WebDriver API,直接控制浏览器 |
| Selenium 3 | 2016 | 独立 ChromeDriver,JSON Wire Protocol |
| Selenium 4 | 2021 | W3C WebDriver 协议标准化,新 API,BiDi 支持 |
| Selenium 4.x (持续更新) | 2023+ | CDP 集成,相对定位器,更好的 DevTools 支持 |
架构总览
┌──────────────────────────────────────────────────────────┐
│ 测试脚本 (Python/Java/etc.) │
├──────────────────────────────────────────────────────────┤
│ Selenium Client Library │
│ (selenium-python / selenium-java / selenium-dotnet) │
├──────────────────────────────────────────────────────────┤
│ W3C WebDriver 协议 │
│ (HTTP/JSON Wire Protocol) │
├────────────────────┬─────────────────────────────────────┤
│ ChromeDriver │ geckodriver │ msedgedriver │
│ (Chrome/Chromium)│ (Firefox) │ (Edge) │
├────────────────────┴─────────────────────────────────────┤
│ Chrome / Chromium │
└──────────────────────────────────────────────────────────┘
3.2 安装 Selenium
Python
pip install selenium
# 验证安装
python -c "import selenium; print(selenium.__version__)"
Java (Maven)
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.16.1</version>
</dependency>
Node.js
npm install selenium-webdriver
C# (.NET)
dotnet add package Selenium.WebDriver
3.3 第一个自动化脚本
Python
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time
# 方式 1: 使用系统 PATH 中的 ChromeDriver
driver = webdriver.Chrome()
# 方式 2: 指定 ChromeDriver 路径
# service = Service('/usr/local/bin/chromedriver')
# driver = webdriver.Chrome(service=service)
# 打开页面
driver.get("https://www.google.com")
# 获取页面信息
print(f"标题: {driver.title}")
print(f"URL: {driver.current_url}")
# 找到搜索框并输入
search_box = driver.find_element(By.NAME, "q")
search_box.send_keys("Selenium WebDriver")
search_box.submit()
time.sleep(2)
print(f"搜索后标题: {driver.title}")
# 关闭浏览器
driver.quit()
Java
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.By;
public class FirstScript {
public static void main(String[] args) {
// 创建 Chrome 驱动
WebDriver driver = new ChromeDriver();
try {
// 打开页面
driver.get("https://www.google.com");
System.out.println("标题: " + driver.getTitle());
// 搜索
driver.findElement(By.name("q")).sendKeys("Selenium WebDriver");
driver.findElement(By.name("q")).submit();
Thread.sleep(2000);
System.out.println("搜索后标题: " + driver.getTitle());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
driver.quit();
}
}
}
Node.js
const { Builder, By, Key, until } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
async function main() {
// 创建驱动
let driver = await new Builder()
.forBrowser('chrome')
.setChromeOptions(new chrome.Options())
.build();
try {
await driver.get('https://www.google.com');
console.log('标题:', await driver.getTitle());
// 搜索
await driver.findElement(By.name('q')).sendKeys('Selenium WebDriver', Key.RETURN);
await driver.wait(until.titleContains('Selenium'), 5000);
console.log('搜索后标题:', await driver.getTitle());
} finally {
await driver.quit();
}
}
main();
3.4 WebDriver 协议详解
请求与响应格式
WebDriver 协议基于 HTTP RESTful API,所有通信均为 JSON 格式。
创建会话请求:
POST /session HTTP/1.1
Content-Type: application/json
{
"capabilities": {
"alwaysMatch": {
"browserName": "chrome",
"goog:chromeOptions": {
"args": ["--headless", "--no-sandbox"]
}
}
}
}
会话响应:
{
"value": {
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"capabilities": {
"browserName": "chrome",
"browserVersion": "120.0.6099.71",
"platformName": "linux",
"goog:chromeOptions": { "debuggerAddress": "127.0.0.1:9222" }
}
}
}
常用 WebDriver 命令
| HTTP 方法 | 路径 | 说明 | Selenium 方法 |
|---|---|---|---|
POST | /session | 创建会话 | webdriver.Chrome() |
DELETE | /session/{id} | 关闭会话 | driver.quit() |
POST | /session/{id}/url | 导航到 URL | driver.get(url) |
GET | /session/{id}/url | 获取当前 URL | driver.current_url |
GET | /session/{id}/title | 获取页面标题 | driver.title |
POST | /session/{id}/element | 查找元素 | driver.find_element() |
POST | /session/{id}/element/{eid}/click | 点击元素 | element.click() |
POST | /session/{id}/element/{eid}/value | 输入文本 | element.send_keys() |
POST | /session/{id}/execute/sync | 执行 JS | driver.execute_script() |
POST | /session/{id}/screenshot | 截图 | driver.get_screenshot_as_png() |
3.5 浏览器选项配置 (ChromeOptions)
ChromeOptions 是配置 Chrome 启动行为的核心类。
Python — 完整配置示例
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
options = Options()
# === 基础选项 ===
options.binary_location = "/usr/bin/google-chrome" # Chrome 二进制路径
options.add_argument("--headless=new") # 无头模式 (新)
options.add_argument("--no-sandbox") # 禁用沙箱 (root 用户必须)
options.add_argument("--disable-dev-shm-usage") # 使用 /tmp 替代 /dev/shm
options.add_argument("--disable-gpu") # 禁用 GPU 加速
# === 窗口与显示 ===
options.add_argument("--window-size=1920,1080") # 窗口大小
options.add_argument("--start-maximized") # 最大化启动
options.add_argument("--force-device-scale-factor=1") # 缩放比例
# === 网络 ===
options.add_argument("--proxy-server=http://proxy:8080") # 代理
options.add_argument("--ignore-certificate-errors") # 忽略证书错误
options.add_argument("--disable-extensions") # 禁用扩展
# === 性能 ===
options.add_argument("--disable-logging") # 禁用日志
options.add_argument("--disable-background-networking") # 禁用后台网络
options.page_load_strategy = 'eager' # 页面加载策略
# === 实验性选项 ===
options.add_experimental_option("prefs", {
"download.default_directory": "/tmp/downloads",
"download.prompt_for_download": False,
"profile.default_content_setting_values.notifications": 2, # 禁用通知
})
# === 附加扩展 ===
options.add_extension("/path/to/extension.crx")
# 创建驱动
driver = webdriver.Chrome(options=options)
Java — 配置示例
ChromeOptions options = new ChromeOptions();
// 基础选项
options.setBinary("/usr/bin/google-chrome");
options.addArguments("--headless=new");
options.addArguments("--no-sandbox");
options.addArguments("--disable-dev-shm-usage");
options.addArguments("--window-size=1920,1080");
// 性能选项
options.addArguments("--disable-extensions");
options.addArguments("--disable-gpu");
// 页面加载策略
options.setPageLoadStrategy(PageLoadStrategy.EAGER);
// 实验性选项
Map<String, Object> prefs = new HashMap<>();
prefs.put("download.default_directory", "/tmp/downloads");
options.setExperimentalOption("prefs", prefs);
ChromeDriver driver = new ChromeDriver(options);
常用 Chrome 启动参数速查
| 参数 | 说明 |
|---|---|
--headless=new | 无头模式(新版,Chrome 112+) |
--headless | 无头模式(旧版,兼容性好) |
--no-sandbox | 禁用沙箱(Docker/root 环境必须) |
--disable-dev-shm-usage | 使用 /tmp 替代 /dev/shm(Docker 必须) |
--disable-gpu | 禁用 GPU 加速(无头模式常用) |
--window-size=W,H | 设置窗口大小 |
--proxy-server=URL | 设置代理服务器 |
--ignore-certificate-errors | 忽略 SSL 证书错误 |
--disable-extensions | 禁用所有扩展 |
--disable-notifications | 禁用通知弹窗 |
--disable-popup-blocking | 禁用弹窗拦截 |
--lang=zh-CN | 设置浏览器语言 |
--user-agent=STRING | 自定义 UserAgent |
--remote-debugging-port=9222 | 启用远程调试端口 |
--user-data-dir=PATH | 指定用户数据目录 |
--profile-directory=NAME | 指定 Profile |
--incognito | 无痕模式 |
--kiosk | 全屏 kiosk 模式 |
--disable-background-timer-throttling | 禁用后台定时器节流 |
--disable-renderer-backgrounding | 禁用渲染器后台降级 |
3.6 页面加载策略
WebDriver 协议定义了三种页面加载策略,影响脚本的等待行为:
| 策略 | 行为 | 适用场景 |
|---|---|---|
normal (默认) | 等待整个页面加载完成(load 事件触发) | 大多数场景 |
eager | 等待 DOM 解析完成(DOMContentLoaded 事件触发) | 需要快速交互 |
none | 不等待任何加载事件 | 完全自定义等待 |
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.page_load_strategy = 'eager' # DOM 就绪即可交互
driver = webdriver.Chrome(options=options)
driver.get("https://example.com") # 不等待图片等资源加载
# 此时即可操作 DOM 元素
3.7 日志与调试
启用 WebDriver 日志
import logging
# 设置 Selenium 日志级别
logging.getLogger('selenium').setLevel(logging.DEBUG)
logging.getLogger('urllib3').setLevel(logging.DEBUG)
获取浏览器日志
options = Options()
options.set_capability("goog:loggingPrefs", {"browser": "ALL"})
driver = webdriver.Chrome(options=options)
driver.get("https://example.com")
# 获取 console.log 输出
logs = driver.get_log("browser")
for entry in logs:
print(f"[{entry['level']}] {entry['message']}")
ChromeDriver 日志级别
# 启动 ChromeDriver 时指定日志级别
chromedriver --log-level=DEBUG --verbose
# 或通过选项
options.add_argument("--enable-logging")
options.add_argument("--v=1") # VLOG 级别 (1-9)
3.8 远程 WebDriver
Selenium 支持通过远程 WebDriver 协议控制远端浏览器,这是 Selenium Grid 的基础。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless=new")
# 连接到远程 Selenium Grid / Standalone
driver = webdriver.Remote(
command_executor="http://selenium-hub:4444/wd/hub",
options=options
)
driver.get("https://example.com")
print(driver.title)
driver.quit()
远程 WebDriver 工作流:
测试脚本 ──HTTP──→ Selenium Server ──CDP──→ Chrome
(本机) (远程/Grid) (远程容器)
3.9 Desired Capabilities vs Options
Selenium 4 中推荐使用 Options 替代旧的 DesiredCapabilities。
| 对比 | DesiredCapabilities (旧) | Options (新) |
|---|---|---|
| Selenium 3 | ✅ 主要方式 | ⚠️ 有限支持 |
| Selenium 4 | ❌ 已废弃 | ✅ 推荐方式 |
| 类型安全 | 无 | 有(每个浏览器独立类) |
| 合并能力 | 手动 merge | set_capability() |
| 代码示例 | caps = DesiredCapabilities.CHROME.copy() | options = ChromeOptions() |
# ❌ 旧方式 (已废弃)
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
caps = DesiredCapabilities.CHROME.copy()
caps['goog:chromeOptions'] = {'args': ['--headless']}
# ✅ 新方式
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument('--headless=new')
3.10 要点回顾
| 要点 | 说明 |
|---|---|
| Selenium 4 使用 W3C 协议 | 不再依赖 JSON Wire Protocol |
| ChromeOptions 配置一切 | 启动参数、扩展、实验性选项都通过它设置 |
| 页面加载策略影响交互 | eager 可以提前操作 DOM,none 完全自控 |
| 远程 WebDriver | 通过 HTTP 连接远程浏览器/Selenium Grid |
| 日志调试 | goog:loggingPrefs 可获取浏览器 console 日志 |
3.11 注意事项
⚠️ Selenium 4 不向后兼容 Selenium 3: API 有较大变化,迁移时需参考官方迁移指南。
⚠️
--headlessvs--headless=new: Chrome 112+ 推荐使用--headless=new,旧的--headless可能缺少某些功能(如扩展加载)。⚠️
driver.quit()vsdriver.close():quit()关闭所有窗口并退出浏览器进程,close()仅关闭当前窗口。务必使用quit()避免僵尸进程。⚠️
--no-sandbox安全风险: 仅在 Docker 或 root 环境下使用,普通用户不应添加此参数。
3.12 扩展阅读
| 资源 | 链接 |
|---|---|
| Selenium 官方文档 | https://www.selenium.dev/documentation/ |
| W3C WebDriver 规范 | https://www.w3.org/TR/webdriver/ |
| Chrome 启动参数列表 | https://peter.sh/experiments/chromium-command-line-switches/ |
| Selenium 4 迁移指南 | https://www.selenium.dev/documentation/webdriver/getting_started/upgrade_to_selenium_4/ |
| ChromeDriver 特性命令行 | https://chromedriver.chromium.org/capabilities |