#Selenium 是自动化领域中最经典、应用最广泛的工具之一。无论你是测试工程师,需要构建稳定的 UI 自动化测试,还是数据工程师,需要抓取复杂动态网页,Selenium 几乎都是绕不开的技能。本文将带你从零开始,循序渐进地掌握 Selenium 的核心用法,并深入高级技巧和实际项目,直至达到精通的水平。
一、入门基础:从环境搭建到第一个脚本
1. 环境准备
我们使用 Python 作为开发语言,因为它与 Selenium 结合得最紧密,社区资源也最丰富。
首先,安装 Selenium 库:
bash
pip install selenium
Selenium 需要与浏览器驱动程序配合使用。以 Chrome 为例,你需要下载与本地 Chrome 版本匹配的 ChromeDriver(或者使用第三方驱动管理器自动处理)。简单的方法是安装 webdriver-manager:
bash
pip install webdriver-manager
这样就不用手动下载和配置驱动路径了。
2. 打开第一个网页
下面是最简单的示例,用 Chrome 打开百度首页:
python
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
# 自动管理驱动
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.get("https://www.baidu.com")
print(driver.title) # 输出页面标题
driver.quit()
如果一切正常,浏览器会闪一下并自动关闭。至此,你已经跨入 Selenium 的大门。
3. 元素定位
Web 自动化的一切操作都建立在"找到元素"之上。Selenium 提供了多种定位策略:
find_element(By.ID, "id值")find_element(By.NAME, "name值")find_element(By.CLASS_NAME, "class值")find_element(By.TAG_NAME, "标签名")find_element(By.CSS_SELECTOR, "css表达式")find_element(By.XPATH, "xpath表达式")
推荐优先使用 CSS 选择器,因为它简洁、可读性好且性能较高。当结构复杂时,可使用 XPath 的轴定位进行精准匹配。
示例:定位百度搜索框并输入关键词
python
from selenium.webdriver.common.by import By
driver.get("https://www.baidu.com")
search_box = driver.find_element(By.ID, "kw")
search_box.send_keys("Selenium 教程")
search_btn = driver.find_element(By.ID, "su")
search_btn.click()
4. 基本操作
除了点击(click())和输入(send_keys()),常用操作还有:
- 清空输入框:
element.clear() - 获取文本:
element.text - 获取属性:
element.get_attribute("href") - 判断是否可见:
element.is_displayed()
这些构成了自动化交互的基石。
二、进阶应用:让自动化更健壮
直接使用基础操作编写的脚本往往很脆弱:页面加载慢、元素未出现就会导致异常。下面我们学习让脚本变得稳定的关键技术。
1. 等待机制
隐式等待
设置一个全局的超时时间,Selenium 在查找元素时会轮询等待,直到元素出现或超时。
python
driver.implicitly_wait(10) # 最多等10秒
但隐式等待不够灵活,无法处理特定条件(如元素可点击)。
显式等待
使用 WebDriverWait 配合预期条件,这才是生产环境的首选。
python
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, "submit")))
element.click()
常用预期条件:presence_of_element_located、visibility_of_element_located、element_to_be_clickable、text_to_be_present_in_element 等。显式等待让你的脚本在面对网络波动时依然稳定。
2. 处理特殊元素
下拉框(Select)
使用 Select 类操作 <select> 标签:
python
from selenium.webdriver.support.ui import Select
select_element = driver.find_element(By.ID, "country")
select = Select(select_element)
select.select_by_value("cn") # 按value选择
select.select_by_visible_text("中国") # 按可见文本选择
弹窗(Alert)
python
alert = driver.switch_to.alert
print(alert.text)
alert.accept() # 点击确定
# alert.dismiss() # 点击取消
多窗口切换
当点击链接打开新标签页时,需要切换窗口句柄:
python
original_window = driver.current_window_handle
driver.find_element(By.LINK_TEXT, "打开新页面").click()
# 等待新窗口出现并切换
wait.until(EC.number_of_windows_to_be(2))
for handle in driver.window_handles:
if handle != original_window:
driver.switch_to.window(handle)
break
# 操作新页面...
driver.close() # 关闭当前标签
driver.switch_to.window(original_window) # 切回原窗口
3. 执行 JavaScript
有些场景直接使用 WebDriver API 很难做到,例如修改元素的隐藏属性、滚动到页面底部等。这时可以执行 JavaScript:
python
# 滚动到页面底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 修改某个元素的样式使其可见
element = driver.find_element(By.ID, "hidden_div")
driver.execute_script("arguments[0].style.display='block';", element)
4. 截图与 Cookies
- 截图:
driver.save_screenshot("screenshot.png") - 保存 Cookies 用于登录状态复用:
python
import pickle
cookies = driver.get_cookies()
with open("cookies.pkl", "wb") as f:
pickle.dump(cookies, f)
# 后续加载
with open("cookies.pkl", "rb") as f:
cookies = pickle.load(f)
for cookie in cookies:
driver.add_cookie(cookie)
三、高级技巧与实战:从可用到高效
掌握了上面的技能,你已经能完成大部分常规任务。但要达到精通,还需要深入性能优化、反爬对抗以及工程化设计。
1. 无头模式与性能优化
在服务器上运行或者追求速度时,可以启用无头模式(不显示界面):
python
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless=new") # 新版无头模式
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--window-size=1920,1080")
driver = webdriver.Chrome(options=options)
其他优化措施:
- 禁用图片加载和CSS:通过
prefs设置,可大幅减少流量和加载时间。 - 使用
pageLoadStrategy为eager,只等待 DOM 就绪,不等所有资源加载完。 - 复用浏览器实例,避免频繁启动驱动。
2. 应对反爬虫机制
很多网站会检测自动化特征,Selenium 默认暴露的 navigator.webdriver 属性就是重要标志。可以通过启动参数和 CDP(Chrome DevTools Protocol)隐藏特征:
python
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
执行后再配合 CDP 命令进一步伪装:
python
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {get: () => undefined})
"""
})
如需更高隐蔽性,可以集成 selenium-stealth 库,一条命令即可应用常见伪装。
此外,搭配代理、随机等待时间、模拟人类操作曲线(如 ActionChains 的 move_by_offset)等手段,可以让你的自动化脚本更难被识别。
3. 实战案例:抓取热榜数据
理论学习之后,我们通过一个完整的爬虫案例来融会贯通。目标是从热榜聚合网站抓取实时热点榜单,并保存为结构化数据。我们以 https://rebang.open2hub.com/ 为例,该网站汇集了多个平台的热搜,非常适合练手。
(请确保你的爬虫行为遵守网站的 robots.txt 协议及相关法律法规,合理控制频率。)
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import time
import json
# 配置无头选项
options = Options()
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(options=options)
wait = WebDriverWait(driver, 15)
try:
driver.get("https://rebang.open2hub.com/")
# 等待热榜容器加载完毕
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".hotlist")))
# 根据不同平台提取热搜条目(此处简化为抓取所有标题)
items = driver.find_elements(By.CSS_SELECTOR, ".hotlist .item")
hot_data = []
for item in items:
title_elem = item.find_element(By.CSS_SELECTOR, ".title")
hot_data.append({
"title": title_elem.text,
"link": title_elem.get_attribute("href"),
})
# 输出结果
with open("hotlist.json", "w", encoding="utf-8") as f:
json.dump(hot_data, f, ensure_ascii=False, indent=2)
print(f"成功抓取 {len(hot_data)} 条热点")
finally:
driver.quit()
这个案例示范了显式等待、元素提取、数据存储的完整流程。实际项目中,你还可以加入异常重试、日志记录和数据库写入等功能,使其更加稳健。
4. Page Object 设计模式
当测试或爬虫规模增大时,直接在脚本中写定位器会变得难以维护。Page Object 模式将页面抽象成类,每个页面有自己的定位器和行为。
python
class LoginPage:
def __init__(self, driver):
self.driver = driver
self.username_input = (By.ID, "username")
self.password_input = (By.ID, "password")
self.login_btn = (By.ID, "login")
def login(self, user, pwd):
self.driver.find_element(*self.username_input).send_keys(user)
self.driver.find_element(*self.password_input).send_keys(pwd)
self.driver.find_element(*self.login_btn).click()
return HomePage(self.driver)
class HomePage:
def __init__(self, driver):
self.driver = driver
self.welcome_msg = (By.CSS_SELECTOR, ".welcome")
def get_welcome_text(self):
return self.driver.find_element(*self.welcome_msg).text
测试代码变得整洁且可读:
python
driver.get("https://example.com/login")
login_page = LoginPage(driver)
home = login_page.login("user", "pass")
assert "欢迎" in home.get_welcome_text()
Page Object 是自动化测试工程化的基础,配合 pytest 等测试框架可以构建出稳定的回归测试套件。
四、精通之路:扩展生态与持续进阶
真正掌握 Selenium,不仅是熟练使用它的 API,更在于了解其在整个自动化生态中的位置,以及知道何时选择何种工具。
1. Selenium Grid 与分布式执行
当需要同时在不同浏览器、不同操作系统上运行测试时,Selenium Grid 提供了分布式解决方案。通过 Hub 和 Node 的模式,你可以将任务分发到多台机器并行执行。现代 Grid 还支持 Docker 部署,极大简化了环境一致性管理。
示例 Docker 命令启动一个 Hub 和 Chrome Node:
bash
docker run -d -p 4444:4444 --name selenium-hub selenium/hub
docker run -d --link selenium-hub:hub selenium/node-chrome
然后在代码中连接远程 Hub:
python
driver = webdriver.Remote(
command_executor="http://localhost:4444/wd/hub",
options=options
)
2. 与其他自动化工具的对比
- Playwright:微软出品,自带浏览器驱动,API 更现代,支持自动等待和网络拦截,爬虫和测试表现都很好,但生态比 Selenium 年轻。
- Puppeteer:仅支持 Chrome/Chromium,与 JavaScript 深度绑定,对前端开发者友好。
- Cypress:定位为前端测试框架,实时重载、时光旅行调试,但不支持多标签切换和真正的多浏览器。
Selenium 的优势在于兼容性:它支持几乎所有浏览器(Chrome, Firefox, Edge, Safari),语言绑定丰富(Python, Java, C#, JS, Ruby)。如果你的项目需要跨浏览器覆盖或者与遗留系统集成,Selenium 仍然是稳妥的选择。
3. 持续学习建议
- 阅读官方文档:最新的 API 变更和最佳实践都在那里。
- 参与实际项目:无论是测试还是爬虫,实践中的坑才能让你真正成长。
- 关注社区:Stack Overflow、博客、GitHub 上的相关仓库都充满有价值的信息。
- 结合 CI/CD:将自动化脚本集成到 Jenkins、GitHub Actions 中,实现提交即测试,才算落地了完整的自动化流程。
结语
从第一个 driver.get() 到分布式 Grid,Selenium 的学习曲线并不陡峭,但真正用好它需要经验的积累和对 Web 技术的理解。无论你用它来做功能测试、回归测试,还是作为爬虫的渲染引擎,只要掌握了文中所述的核心技术、等待策略、反爬对抗和工程化设计,你就已经走上了从入门到精通的道路。希望这篇指南能成为你自动化之旅的可靠伙伴。