Selenium 自动化浏览器:动态页面抓取与测试

FreeGuideOnline 最新 2026-06-16

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 框架。

测试场景:登录功能

  1. 打开登录页
  2. 输入用户名和密码
  3. 点击登录
  4. 验证是否跳转到首页或显示欢迎信息
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 解锁全自动浏览器体验吧!