Selenium Python 完整教程:从入门到实战
目录
- 第一部分:入门基础
- 什么是 Selenium?
- 为什么选择 Selenium Python?
- 环境准备
- 你的第一个脚本:打开并关闭浏览器
- 第二部分:核心元素定位
- 为什么要定位元素?
- 八大定位方式详解
- 定不到元素怎么办?(调试技巧)
- 第三部分:元素操作与交互
- 基本操作:点击、输入、清空
- 特殊操作:下拉框、弹窗、文件上传
- 等待机制:显式等待 vs 隐式等待
- 第四部分:获取页面信息
- 获取元素文本
- 获取元素属性
- 获取页面标题和 URL
- 第五部分:高级功能与实战技巧
- 处理多窗口/多标签页
- 执行 JavaScript
- 页面截图与元素截图
- 无头模式
- 使用 ActionChains 处理鼠标事件
- 第六部分:项目实战:爬取知乎热榜
- 需求分析
- 代码实现
- 代码解析
- 第七部分:最佳实践与常见问题
- 代码结构优化
- 常见异常与解决方案
- 反爬虫对策简介
第一部分:入门基础
什么是 Selenium?
Selenium 是一个用于 Web 应用程序的自动化测试工具,它可以直接在浏览器中运行,就像一个真实用户在操作一样,你可以用它来模拟点击、输入、滚动等行为,从而实现网页的自动化操作。

为什么选择 Selenium Python?
- 语法简洁:Python 以其简洁易读的语法著称,非常适合编写自动化脚本。
- 生态丰富:拥有强大的第三方库支持,可以轻松集成到各种项目中。
- 社区活跃:遇到问题时,很容易在 Stack Overflow、GitHub 等社区找到解决方案。
环境准备
步骤 1:安装 Python
确保你的电脑上已经安装了 Python (推荐 3.6+ 版本),在终端或命令行中输入 python --version 检查。
步骤 2:安装 Selenium 库
打开终端或命令行,使用 pip 进行安装:

pip install selenium
步骤 3:下载浏览器驱动
Selenium 本身不控制浏览器,它需要通过一个叫 WebDriver 的中间件来与浏览器通信,你需要为你的浏览器下载对应的驱动。
- Chrome 浏览器驱动:
- 访问 Chrome for Testing availability。
- 找到与你 Chrome 浏览器版本(在
设置 -> Chrome中查看)最匹配的chromedriver。 - 下载对应你操作系统(win32, win64, mac-x64, mac-arm64, linux64)的
zip压缩包。 - 关键步骤:将解压后的
chromedriver.exe(Windows) 或chromedriver(Mac/Linux) 文件放到一个固定的路径下(C:\WebDriver),或者将其所在目录添加到系统的PATH环境变量中,这样 Python 就能找到它。
注意:驱动版本必须与浏览器版本高度兼容,否则可能无法启动。
你的第一个脚本:打开并关闭浏览器
创建一个名为 first_script.py 的文件,并输入以下代码:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
# 使用 webdriver_manager 自动管理驱动(推荐,无需手动下载)
# 如果手动下载了驱动并配置了PATH,可以使用下面的方式
# driver = webdriver.Chrome()
# 自动下载并配置驱动
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
# 1. 打开百度首页
driver.get("https://www.baidu.com")
# 2. 打印页面标题
print("页面标题是:", driver.title)
# 3. 关闭浏览器
driver.quit()
运行脚本:
在终端中执行 python first_script.py。
你应该看到: 一个 Chrome 浏览器窗口自动打开,访问百度首页,打印出 "页面标题是: 百度一下,你就知道",然后浏览器自动关闭。
提示:
webdriver-manager是一个非常方便的库,可以自动帮你下载和管理与浏览器版本匹配的驱动,强烈推荐使用!
第二部分:核心元素定位
自动化脚本的核心就是告诉 Selenium 要操作哪个页面元素,这就需要通过“定位”来找到它。
八大定位方式
假设我们要定位百度搜索框 <input id="kw" class="s_ipt" ...>。
| 定位方式 | 代码示例 | 描述 |
|---|---|---|
| ID | driver.find_element(By.ID, "kw") |
通过元素的 id 属性定位,最快最推荐。 |
| Name | driver.find_element(By.NAME, "wd") |
通过元素的 name 属性定位。 |
| Class Name | driver.find_element(By.CLASS_NAME, "s_ipt") |
通过元素的 class 属性定位。 |
| Tag Name | driver.find_element(By.TAG_NAME, "input") |
通过元素的标签名定位,通常用于定位一组元素。 |
| Link Text | driver.find_element(By.LINK_TEXT, "新闻") |
用于定位超链接(<a> 标签),通过完整的文本内容。 |
| Partial Link Text | driver.find_element(By.PARTIAL_LINK_TEXT, "闻") |
用于定位超链接,通过部分文本内容。 |
| CSS Selector | driver.find_element(By.CSS_SELECTOR, "#kw") |
非常强大和灵活,可以使用 ID (#id)、Class (.class)、属性 ([attr=value])、层级 (parent > child) 等方式。 |
| XPath | driver.find_element(By.XPATH, "//*[@id='kw']") |
功能最强大,可以在整个文档树中查找元素,路径灵活。 |
示例代码:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
# 1. 通过ID定位搜索框
search_box_by_id = driver.find_element(By.ID, "kw")
# 2. 通过CSS Selector定位搜索框
search_box_by_css = driver.find_element(By.CSS_SELECTOR, "#kw")
# 3. 通过XPath定位搜索框
search_box_by_xpath = driver.find_element(By.XPATH, '//*[@id="kw"]')
# ... 后续操作 ...
driver.quit()
注意:
find_element是定位单个元素,如果找不到会抛出NoSuchElementException异常,如果需要定位一组元素(如多个复选框),请使用find_elements(注意是 elements,复数),它会返回一个列表。
定不到元素怎么办?
- 检查定位器是否正确:在浏览器开发者工具 (F12) 的 Console 中,使用 或 来测试你的 CSS Selector 或 XPath。
- 测试 CSS:
document.querySelector("#kw") - 测试 XPath:
$x("//*[@id='kw']")
- 测试 CSS:
- 检查 iframe:如果元素在
<iframe>标签内,必须先switch_to.frame()切换到对应的 iframe,才能定位到内部元素。driver.switch_to.frame("frame_name") # 或传入 index 或 WebElement 对象 # ... 在 iframe 内定位元素 ... driver.switch_to.default_content() # 操作完后切回主页面 - 元素未加载完成:页面是异步加载的,脚本执行时元素可能还没出现。请使用等待机制(见第三部分)。
- 被动态生成:元素可能是通过 JavaScript 动态添加到 DOM 中的,确保它在你的操作时机之后出现。
第三部分:元素操作与交互
找到元素后,就可以对它进行操作了。
基本操作
# 假设已经定位到 search_box 和 search_button 元素
search_box = driver.find_element(By.ID, "kw")
search_button = driver.find_element(By.ID, "su")
# 1. 输入文本
search_box.send_keys("Selenium Python 教程")
# 2. 清空输入框(可选)
search_box.clear()
# 3. 点击按钮
search_button.click()
特殊操作
-
下拉框:使用
Select类。from selenium.webdriver.support.ui import Select select_element = driver.find_element(By.ID, "select_id") select = Select(select_element) # 通过索引选择 (从0开始) select.select_by_index(1) # 通过 value 值选择 select.select_by_value("value_2") # 通过可见文本选择 select.select_by_visible_text("Option 3") -
弹窗:需要先切换到弹窗句柄。
# 触发一个 alert driver.find_element(By.ID, "alert_button").click() # 切换到 alert alert = driver.switch_to.alert # 获取 alert 文本 print(alert.text) # 接受 (点击"确定") alert.accept() # 或 取消 (点击"取消") # alert.dismiss()
-
文件上传:
<input>标签的type是file,直接用send_keys发送文件路径即可。file_input = driver.find_element(By.ID, "file_upload_input") file_input.send_keys("C:/path/to/your/file.txt")
等待机制
这是自动化脚本稳定性的关键!
-
隐式等待:
- 作用:在查找元素时,如果元素没有立刻找到,Selenium 会等待一个指定的时间,然后再尝试查找,全局生效。
- 缺点:它只对
find_element和find_elements方法有效,并且是轮询机制,会浪费等待时间。driver.implicitly_wait(10) # 全局等待10秒
-
显式等待:
- 作用:专门为某个条件的出现而等待,更智能、更精确。
- 推荐:在绝大多数情况下,优先使用显式等待。
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC
try:
等待最多10秒,直到ID为"kw"的元素可见并且可交互
search_box = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "kw")) ) search_box.send_keys("Hello Selenium")except TimeoutException: print("元素在指定时间内未出现!")
expected_conditions (EC) 提供了很多有用的条件,
EC.presence_of_element_located: 元素存在于 DOM 中。EC.visibility_of_element_located: 元素可见(不仅存在于DOM,而且CSS属性display等不为none)。EC.element_to_be_clickable: 元素可被点击(可见且enabled)。EC.title_is: 页面标题等于某值。
第四部分:获取页面信息
执行操作后,我们通常需要获取操作结果或页面状态。
# 假设已经执行了搜索
driver.get("https://www.baidu.com")
driver.find_element(By.ID, "kw").send_keys("Selenium")
driver.find_element(By.ID, "su").click()
# 1. 获取元素的文本内容
# 获取第一条搜索结果的标题
first_result = driver.find_element(By.CSS_SELECTOR, "#content_left > .result")
print("第一条结果标题:", first_result.text)
# 2. 获取元素的属性
search_box = driver.find_element(By.ID, "kw")
print("搜索框的 name 属性:", search_box.get_attribute("name"))
print("搜索框的 ID 属性:", search_box.get_attribute("id"))
# 3. 获取页面标题和当前URL
print("当前页面标题:", driver.title)
print("当前页面URL:", driver.current_url)
第五部分:高级功能与实战技巧
处理多窗口/多标签页
当点击链接打开一个新窗口或新标签页时,需要切换句柄。
# 获取当前所有窗口的句柄
original_window = driver.current_window_handle
# 点击一个会打开新窗口的链接
driver.find_element(By.LINK_TEXT, "打开新窗口").click()
# 获取所有窗口句柄
for handle in driver.window_handles:
if handle != original_window:
new_window = handle
break
# 切换到新窗口
driver.switch_to.window(new_window)
# 在新窗口中操作...
print("新窗口标题:", driver.title)
# 关闭新窗口
driver.close()
# 切换回原始窗口
driver.switch_to.window(original_window)
执行 JavaScript
Selenium 可以直接在浏览器中执行任意 JavaScript 代码,功能非常强大。
# 滚动到页面底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 滚动到页面顶部
driver.execute_script("window.scrollTo(0, 0);")
# 获取某个元素的文本(虽然可以用 selenium 自带方法,但展示了 JS 执行)
element_text = driver.execute_script("return document.getElementById('kw').getAttribute('placeholder');")
print("搜索框placeholder:", element_text)
页面截图与元素截图
在脚本出错或调试时,截图非常有用。
from selenium.webdriver.common.by import By
# 页面截图
driver.save_screenshot("baidu_page.png")
# 元素截图
search_box = driver.find_element(By.ID, "kw")
search_box.screenshot("search_box.png")
无头模式
在不打开浏览器界面的情况下运行脚本,适用于服务器环境。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument("--headless") # 启用无头模式
chrome_options.add_argument("--disable-gpu") # 某些系统需要禁用GPU加速
driver = webdriver.Chrome(options=chrome_options)
driver.get("https://www.baidu.com")
print("无头模式下获取标题:", driver.title)
driver.quit()
使用 ActionChains 处理鼠标事件
用于模拟复杂的鼠标操作,如悬停、拖拽、右键点击等。
from selenium.webdriver.common.action_chains import ActionChains # 假设有一个需要悬停才能显示的下拉菜单 menu = driver.find_element(By.ID, "menu_id") sub_menu = driver.find_element(By.ID, "sub_menu_id") # 鼠标悬停 ActionChains(driver).move_to_element(menu).perform() # 等待子菜单出现后点击 WebDriverWait(driver, 10).until(EC.visibility_of(sub_menu)) sub_menu.click() # 拖拽示例 element_to_drag = driver.find_element(By.ID, "draggable") element_to_drop_on = driver.find_element(By.ID, "droppable") ActionChains(driver).drag_and_drop(element_to_drag, element_to_drop_on).perform()
第六部分:项目实战:爬取知乎热榜
需求分析
- 访问知乎热榜页面:
https://www.zhihu.com/hot - 解析页面,获取每个热榜条目的标题、热度、简介等信息。
- 将这些信息打印出来或保存到文件中。
代码实现
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from selenium.common.exceptions import TimeoutException
def get_zhihu_hot_list():
"""
使用Selenium爬取知乎热榜
"""
# 初始化WebDriver
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
# 访问知乎热榜页面
driver.get("https://www.zhihu.com/hot")
# 由于知乎有登录弹窗等,等待一下确保页面加载
# 实际项目中应使用显式等待
time.sleep(5)
hot_list = []
try:
# 热榜条目都在一个 class 为 HotItem 的 div 列表中
# 注意:知乎的页面结构可能会变,这里需要根据实际情况调整选择器
items = driver.find_elements(By.CSS_SELECTOR, ".HotItem")
for item in items:
try:
# 标题
title_element = item.find_element(By.CSS_SELECTOR, ".HotItem-title")
title = title_element.text
# 热度
# 热度数字在 HotItem-index 之后的兄弟元素中,结构可能较复杂
# 这里我们用一个更通用的方法,通过文本提取数字
heat_text = item.text
heat = ""
for char in heat_text:
if char.isdigit():
heat += char
elif heat: # 数字提取完毕
break
# 简介
excerpt = item.find_element(By.CSS_SELECTOR, ".HotItem-excerpt").text
hot_list.append({
"title": title,
"heat": heat,
"excerpt": excerpt
})
except Exception as e:
print(f"解析单个条目时出错: {e}")
continue
except TimeoutException:
print("页面加载超时或元素未找到!")
except Exception as e:
print(f"发生未知错误: {e}")
finally:
# 关闭浏览器
driver.quit()
return hot_list
if __name__ == "__main__":
hot_list = get_zhihu_hot_list()
print(f"共爬取到 {len(hot_list)} 条热榜信息:")
for i, item in enumerate(hot_list, 1):
print(f"\n--- 第 {i} 条 ---")
print(f"标题: {item['title']}")
print(f"热度: {item['heat']}")
print(f"简介: {item['excerpt']}")
代码解析
- 初始化:使用
webdriver-manager自动配置 Chrome 驱动。 - 访问页面:
driver.get()打开目标 URL。 - 等待:这里为了简单使用了
time.sleep(),在生产代码中应替换为显式等待,例如等待.HotItem列表出现。 - 定位元素:使用
find_elements定位所有热榜条目的容器div。 - 循环解析:遍历每个条目,再次使用
find_element定位其内部的标题、热度、简介等元素,并提取文本内容。 - 异常处理:使用
try-except块来增强脚本的健壮性,避免因单个元素解析失败而中断整个程序。 - 清理:
driver.quit()确保浏览器被正确关闭,释放资源。
第七部分:最佳实践与常见问题
代码结构优化
不要把所有代码都写在一个文件里,使用面向对象的方式组织代码,可读性和复用性更高。
# zhihu_crawler.py
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
class ZhihuHotCrawler:
def __init__(self):
self.driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
self.wait = WebDriverWait(self.driver, 10)
def get_hot_list(self):
self.driver.get("https://www.zhihu.com/hot")
# 使用显式等待
self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".HotItem")))
# ... (解析逻辑) ...
return hot_list
def close(self):
self.driver.quit()
# main.py
from zhihu_crawler import ZhihuHotCrawler
if __name__ == "__main__":
crawler = ZhihuHotCrawler()
try:
data = crawler.get_hot_list()
# ... 处理数据 ...
finally:
crawler.close()
常见异常与解决方案
| 异常 | 原因 | 解决方案 |
|---|---|---|
NoSuchElementException |
元素未找到 | 检查定位器、等待时间、iframe、动态加载。 |
SessionNotCreatedException |
WebDriver 版本与浏览器不兼容 | 下载匹配的驱动版本,或使用 webdriver-manager。 |
ElementNotInteractableException |
元素存在但不可交互(被遮挡、不可见、被禁用) | 检查元素是否可见,是否有其他元素覆盖它。 |
TimeoutException |
显式等待超时 | 调整等待时间,或检查等待条件是否正确。 |
StaleElementReferenceException |
元素已经过时(页面刷新后引用了旧元素) | 在每次操作前都重新定位该元素。 |
反爬虫对策简介
大型网站都有反爬虫机制,Selenium 虽然能模拟浏览器,但仍可能被识别。
-
设置 User-Agent:将你的脚本伪装成正常浏览器。
options = webdriver.ChromeOptions() options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36") driver = webdriver.Chrome(options=options) -
使用代理 IP:防止因请求频率过高而被封禁 IP。
options.add_argument("--proxy-server=http://your_proxy_address:port") -
控制访问频率:在请求之间加入随机延迟。
import random time.sleep(random.uniform(1, 3))
-
使用 undetected-chromedriver:这是一个专门为绕过反爬虫检测而设计的 WebDriver 库,它通过修改 Chrome 启动参数来避免被检测为自动化工具。
这份教程已经涵盖了 Selenium Python 自动化的核心知识点,要成为一名高手,最好的方法就是 多练习、多实践,尝试去爬取你感兴趣的网站,或者为你自己重复性的网页工作编写自动化脚本,在实践中,你会遇到各种各样的问题,解决它们的过程就是最好的学习过程。
祝你学习愉快!
