Selenium 自动化浏览器:动态页面抓取与测试
Selenium 自动化浏览器:动态页面抓取与测试
教程目标
本教程将带你从零开始掌握 Selenium,学会如何用代码操控浏览器,实现动态页面数据抓取与自动化测试。你将能够:
- 理解 Selenium 的核心原理与适用场景
- 安装并配置浏览器驱动
- 使用 Python 编写基础自动化脚本
- 精准定位页面元素并与之交互
- 处理动态加载内容与异步数据
- 编写可维护的测试用例
什么是 Selenium?为什么需要它?
Selenium 是一个开源的浏览器自动化框架,它通过调用浏览器原生 API 模拟用户操作。与直接发送 HTTP 请求的工具(如 requests)不同,Selenium 能完整执行页面的 JavaScript,适用于以下场景:
- 动态内容抓取:传统爬虫无法获取由 Ajax 或前端框架(React/Vue)渲染的数据,Selenium 可等待页面渲染完毕再提取内容。
- 自动化测试:模拟点击、输入、拖拽等用户行为,验证 Web 应用的功能是否正常。
- 重复性任务:如表单自动填写、数据批量下载等。
安装与环境配置
1. 安装 Selenium 库
在终端中执行:
pip install selenium
2. 下载浏览器驱动
Selenium 通过“驱动程序”与浏览器通信。你需要根据本地浏览器版本下载对应的驱动:
| 浏览器 | 驱动下载地址 |
|---|---|
| Chrome | ChromeDriver |
| Firefox | GeckoDriver |
下载后,将驱动文件放在系统 PATH 所包含的目录中,或在代码中显式指定路径。
版本匹配非常重要,否则会出现启动错误。
3. 验证安装
新建 Python 脚本 hello_selenium.py:
from selenium import webdriver
driver = webdriver.Chrome() # 如果驱动未在 PATH 中,使用 webdriver.Chrome(executable_path='你的路径')
driver.get("https://www.example.com")
print(driver.title)
driver.quit()
运行后应打印出页面标题,并看到浏览器自动打开、关闭。
第一个自动化脚本:打开网页并截图
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
# 可选配置:无头模式(不显示浏览器界面)
options = Options()
options.add_argument('--headless=new') # 新版 Chrome 推荐
options.add_argument('--no-sandbox')
driver = webdriver.Chrome(options=options)
driver.get("https://www.python.org")
driver.save_screenshot('python_home.png')
driver.quit()
无头模式非常适合在服务器或后台运行自动化任务。
元素定位:找到你想操作的页面元素
Selenium 提供多种定位方式,推荐使用相对定位和唯一属性。
常用方法
find_element(By.ID, "id值")find_element(By.NAME, "name属性")find_element(By.CLASS_NAME, "类名")find_element(By.CSS_SELECTOR, "选择器")find_element(By.XPATH, "XPath表达式")
例:定位百度搜索框并输入内容
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
# 通过 ID 定位
search_input = driver.find_element(By.ID, "kw")
search_input.send_keys("Selenium 教程")
# 通过 name 定位(与 ID 类似)
# search_input = driver.find_element(By.NAME, "wd")
# 提交表单
search_input.submit()
# 或者找到“百度一下”按钮并点击
# driver.find_element(By.ID, "su").click()
driver.quit()
CSS 选择器与 XPath 使用技巧
- CSS:复制元素的选择器(浏览器 DevTools → 右键 → Copy → Copy selector)但可能过于冗长,建议手动编写短小的选择器,如
input.s_ipt。 - XPath:适应性更强,可基于文本内容定位。例如:
driver.find_element(By.XPATH, "//button[contains(text(),'登录')]") driver.find_element(By.XPATH, "//a[@href='/login']")
等待机制:处理动态加载的页面
动态页面常需时间渲染数据,如果抓取时机过早会失败。Selenium 提供两种等待方式:
1. 显式等待(推荐)
指定某个条件成立后再继续,最灵活。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver.get("https://dynamic-site.com")
wait = WebDriverWait(driver, 10)
element = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "content"))
)
# 现在可以安全操作 element
常用内置条件:
presence_of_element_located:元素存在于 DOM(不一定是可见)visibility_of_element_located:元素可见element_to_be_clickable:元素可点击text_to_be_present_in_element:特定文本出现
2. 隐式等待
设置一个全局等待时间,当查找元素时如果没立即找到,会等待一段时间再试。
driver.implicitly_wait(10) # 最多等待10秒
不建议和显式等待混用。
3. 固定休眠(避免使用)
time.sleep(5) 会强制等待固定时间,降低脚本效率且不稳定。
动态页面抓取实战:获取 JavaScript 渲染的数据
很多网站通过 API 加载数据再用 JS 渲染到页面。Selenium 配合解析库(如 BeautifulSoup)可高效提取。
目标示例:抓取一个动态加载的新闻列表
页面初始 HTML 不包含新闻条目,它们通过 XHR 请求后插入。
import time
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 bs4 import BeautifulSoup
driver = webdriver.Chrome()
driver.get("https://example-news-site.com")
# 等待列表容器出现
wait = WebDriverWait(driver, 15)
container = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "ul.news-list"))
)
# 有时候数据是滚动加载的,可执行 JS 滚动到底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 给一点时间让新内容加载
wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "li.news-item")))
# 也可使用 time.sleep(2) 作为最终保障
# 获取完整渲染后的页面源代码
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
# 提取所需数据
for item in soup.select("li.news-item"):
title = item.find("h3").text.strip()
link = item.find("a")["href"]
print(f"标题:{title}\n链接:{link}\n")
driver.quit()
直接执行 JavaScript 提取数据
有时更简洁:
# 返回某个 JavaScript 变量的值
data = driver.execute_script("return window.__INITIAL_STATE__;")
编写可维护的自动化测试用例
Selenium 也常用于 Web 应用测试。下面是一个简单的测试示例,使用 Python 的 unittest 框架。
测试场景:登录功能
- 打开登录页
- 输入用户名和密码
- 点击登录
- 验证是否跳转到首页或显示欢迎信息
import unittest
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
class LoginTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://example.com/login")
self.wait = WebDriverWait(self.driver, 10)
def test_successful_login(self):
driver = self.driver
# 定位元素
username = driver.find_element(By.ID, "username")
password = driver.find_element(By.ID, "password")
login_btn = driver.find_element(By.XPATH, "//button[@type='submit']")
# 用户操作
username.send_keys("testuser@example.com")
password.send_keys("secret123")
login_btn.click()
# 断言:登录后应出现“欢迎”文本
welcome_msg = self.wait.until(
EC.visibility_of_element_located((By.CLASS_NAME, "welcome-msg"))
)
self.assertEqual(welcome_msg.text, "欢迎回来,Test User")
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
最佳实践:
- 使用 Page Object 模式将页面元素和操作封装成类,减少重复代码。
- 测试数据与用例分离。
- 结合截图功能,在测试失败时自动保存现场。
常见问题与进阶技巧
1. 如何避免被网站检测?
- 添加
options.add_argument('--disable-blink-features=AutomationControlled') - 移除
navigator.webdriver标记(需高级反检测) - 使用
undetected-chromedriver等封装库
2. 处理弹窗(Alert)
alert = driver.switch_to.alert
print(alert.text)
alert.accept() # 点击确认
alert.dismiss() # 取消
3. 切换 iframe
driver.switch_to.frame("frame_name_or_element")
# 操作 iframe 内的元素
driver.switch_to.default_content() # 返回主文档
4. 窗口和标签页管理
# 获取所有窗口句柄
handles = driver.window_handles
driver.switch_to.window(handles[1])
driver.close() # 关闭当前标签页
5. 截图与性能
driver.get_screenshot_as_file('fullpage.png')仅截取当前视口,需要全页截图可使用execute_script结合图片拼接库。- 无头模式下资源加载可能更快,但某些动态交互可能需要等待更精确的条件。
总结
Selenium 是浏览器自动化的瑞士军刀,掌握了元素定位、等待策略和与解析库的配合,你就能应对绝大多数动态页面抓取与测试需求。从简单的表单提交到复杂的单页应用测试,坚持书写稳健的显式等待和清晰的定位器,你的脚本将变得可靠且易于维护。
开始用 Selenium 解锁全自动浏览器体验吧!