从入门到精通:Python Selenium 模拟浏览器操作完整指南
一、Selenium 概述
1.1 什么是 Selenium?
Selenium 是一个用于 Web 应用程序测试的自动化工具,支持多种浏览器和编程语言,通过模拟真实用户操作实现自动化。
1.2 主要组件
- Selenium WebDriver:核心组件,提供浏览器控制 API
- Selenium Grid:分布式测试工具
- Selenium IDE:浏览器插件,录制回放工具
二、环境搭建
2.1 安装必要库
# 安装 Selenium
pip install selenium
# 安装浏览器驱动管理器(推荐)
pip install webdriver-manager
2.2 浏览器驱动配置
# 方法1:手动下载驱动(需要匹配浏览器版本)
# Chrome: https://chromedriver.chromium.org/
# Firefox: https://github.com/mozilla/geckodriver/releases
# 方法2:使用 webdriver-manager(自动管理驱动)
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
三、基础操作
3.1 启动浏览器
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
# 基础启动
driver = webdriver.Chrome()
# 带配置启动
chrome_options = Options()
chrome_options.add_argument('--headless') # 无头模式
chrome_options.add_argument('--disable-gpu') # 禁用GPU
chrome_options.add_argument('--window-size=1920x1080') # 窗口大小
driver = webdriver.Chrome(options=chrome_options)
# 访问网页
driver.get('https://www.baidu.com')
3.2 元素定位
# 八大定位方式
# 1. ID
element = driver.find_element(By.ID, "kw")
# 2. Name
element = driver.find_element(By.NAME, "wd")
# 3. Class Name
element = driver.find_element(By.CLASS_NAME, "s_ipt")
# 4. Tag Name
elements = driver.find_elements(By.TAG_NAME, "input")
# 5. Link Text(完整链接文本)
element = driver.find_element(By.LINK_TEXT, "新闻")
# 6. Partial Link Text(部分链接文本)
element = driver.find_element(By.PARTIAL_LINK_TEXT, "闻")
# 7. XPath(最常用)
element = driver.find_element(By.XPATH, "//input[@id='kw']")
element = driver.find_element(By.XPATH, "//div[@class='s_form']/form/span[1]/input")
# 8. CSS Selector
element = driver.find_element(By.CSS_SELECTOR, "#kw")
element = driver.find_element(By.CSS_SELECTOR, ".s_ipt")
3.3 常用操作
# 输入文本
search_box = driver.find_element(By.ID, "kw")
search_box.send_keys("Python Selenium教程")
search_box.clear() # 清空输入框
search_box.send_keys("新的搜索词")
# 点击操作
search_button = driver.find_element(By.ID, "su")
search_button.click()
# 提交表单
search_box.submit()
# 获取元素属性
value = search_box.get_attribute("value")
class_name = search_box.get_attribute("class")
# 获取文本内容
text = driver.find_element(By.XPATH, "//h3").text
# 判断元素状态
is_displayed = search_box.is_displayed() # 是否显示
is_enabled = search_box.is_enabled() # 是否可用
is_selected = search_box.is_selected() # 是否选中(复选框/单选框)
四、高级操作
4.1 等待机制
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 隐式等待(全局等待)
driver.implicitly_wait(10) # 最多等待10秒
# 显式等待(针对特定条件)
wait = WebDriverWait(driver, 10)
# 等待元素出现
element = wait.until(EC.presence_of_element_located((By.ID, "kw")))
# 等待元素可点击
element = wait.until(EC.element_to_be_clickable((By.ID, "su")))
# 等待元素可见
element = wait.until(EC.visibility_of_element_located((By.ID, "kw")))
# 等待页面标题包含特定文本
wait.until(EC.title_contains("Python"))
# 常用条件列表
# presence_of_element_located - 元素出现
# visibility_of_element_located - 元素可见
# element_to_be_clickable - 元素可点击
# text_to_be_present_in_element - 元素包含特定文本
# alert_is_present - 弹窗出现
4.2 处理弹窗和警告框
# 获取警告框
alert = driver.switch_to.alert
# 获取文本
alert_text = alert.text
# 接受警告框
alert.accept()
# 拒绝警告框
alert.dismiss()
# 输入文本(prompt类型)
alert.send_keys("输入文本")
# 处理确认框
try:
alert = driver.switch_to.alert
alert.accept() # 点击确定
except:
print("没有弹窗")
4.3 处理iframe
# 切换到iframe
driver.switch_to.frame("iframe_id") # 通过id
driver.switch_to.frame("iframe_name") # 通过name
driver.switch_to.frame(0) # 通过索引
driver.switch_to.frame(driver.find_element(By.TAG_NAME, "iframe")) # 通过元素
# 返回主文档
driver.switch_to.default_content()
# 返回上级iframe
driver.switch_to.parent_frame()
4.4 处理多窗口
# 获取当前窗口句柄
current_window = driver.current_window_handle
# 获取所有窗口句柄
all_windows = driver.window_handles
# 切换到新窗口
for window in all_windows:
if window != current_window:
driver.switch_to.window(window)
break
# 关闭当前窗口并切换回原窗口
driver.close()
driver.switch_to.window(current_window)
4.5 执行JavaScript
# 执行JavaScript
driver.execute_script("alert('Hello Selenium');")
# 滚动页面
# 滚动到底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 滚动到顶部
driver.execute_script("window.scrollTo(0, 0);")
# 滚动到元素
element = driver.find_element(By.ID, "element_id")
driver.execute_script("arguments[0].scrollIntoView();", element)
# 修改元素属性
driver.execute_script("arguments[0].setAttribute('style', 'color: red');", element)
# 获取页面信息
page_height = driver.execute_script("return document.body.scrollHeight")
4.6 Cookie操作
# 获取所有cookies
cookies = driver.get_cookies()
for cookie in cookies:
print(cookie['name'], cookie['value'])
# 获取指定cookie
value = driver.get_cookie('cookie_name')['value']
# 添加cookie
driver.add_cookie({'name': 'test', 'value': '123'})
# 删除cookie
driver.delete_cookie('cookie_name')
# 删除所有cookies
driver.delete_all_cookies()
五、实战案例
5.1 自动化登录示例
def login_website(username, password):
"""
自动化登录示例
"""
driver = webdriver.Chrome()
try:
# 访问登录页面
driver.get("https://example.com/login")
# 等待页面加载
wait = WebDriverWait(driver, 10)
# 输入用户名
username_input = wait.until(
EC.presence_of_element_located((By.NAME, "username"))
)
username_input.send_keys(username)
# 输入密码
password_input = driver.find_element(By.NAME, "password")
password_input.send_keys(password)
# 点击登录按钮
login_button = driver.find_element(By.XPATH, "//button[@type='submit']")
login_button.click()
# 验证登录成功
wait.until(EC.url_contains("dashboard"))
print("登录成功!")
# 保存截图
driver.save_screenshot("login_success.png")
except Exception as e:
print(f"登录失败: {e}")
driver.save_screenshot("login_error.png")
finally:
driver.quit()
# 使用示例
login_website("your_username", "your_password")
5.2 数据爬取示例
def scrape_news():
"""
爬取新闻网站示例
"""
driver = webdriver.Chrome()
driver.get("https://news.baidu.com")
news_data = []
try:
# 等待新闻列表加载
wait = WebDriverWait(driver, 10)
news_list = wait.until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".hotnews a"))
)
# 提取新闻信息
for index, news in enumerate(news_list[:10]): # 只取前10条
title = news.text
link = news.get_attribute("href")
# 点击进入详情页(新标签页打开)
news.click()
driver.switch_to.window(driver.window_handles[-1])
# 获取详情页内容
time.sleep(2) # 等待页面加载
try:
content_element = driver.find_element(By.CLASS_NAME, "article-content")
content = content_element.text[:200] # 取前200字符
except:
content = "无法获取内容"
news_data.append({
"序号": index + 1,
"标题": title,
"链接": link,
"内容预览": content
})
# 关闭详情页标签,返回列表页
driver.close()
driver.switch_to.window(driver.window_handles[0])
except Exception as e:
print(f"爬取失败: {e}")
finally:
driver.quit()
return news_data
# 使用示例
data = scrape_news()
for item in data:
print(f"{item['序号']}. {item['标题']}")
六、高级技巧与优化
6.1 反反爬虫策略
chrome_options = Options()
# 添加用户代理
chrome_options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
# 禁用自动化标志
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
# 添加其他反检测参数
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
# 使用代理
chrome_options.add_argument('--proxy-server=http://your-proxy:port')
driver = webdriver.Chrome(options=chrome_options)
# 执行JS修改navigator.webdriver属性
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
6.2 性能优化
# 禁用图片加载
prefs = {"profile.managed_default_content_settings.images": 2}
chrome_options.add_experimental_option("prefs", prefs)
# 禁用JavaScript(谨慎使用)
chrome_options.add_experimental_option("prefs", {
'profile.managed_default_content_settings.javascript': 2
})
# 使用无头模式
chrome_options.add_argument('--headless')
6.3 使用Page Object模式
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class LoginPage:
"""登录页面对象"""
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
# 定位器
USERNAME_INPUT = (By.NAME, "username")
PASSWORD_INPUT = (By.NAME, "password")
LOGIN_BUTTON = (By.XPATH, "//button[@type='submit']")
ERROR_MESSAGE = (By.CLASS_NAME, "error-message")
def enter_username(self, username):
"""输入用户名"""
element = self.wait.until(EC.presence_of_element_located(self.USERNAME_INPUT))
element.clear()
element.send_keys(username)
return self
def enter_password(self, password):
"""输入密码"""
element = self.driver.find_element(*self.PASSWORD_INPUT)
element.clear()
element.send_keys(password)
return self
def click_login(self):
"""点击登录"""
element = self.driver.find_element(*self.LOGIN_BUTTON)
element.click()
return self
def get_error_message(self):
"""获取错误信息"""
try:
element = self.wait.until(EC.visibility_of_element_located(self.ERROR_MESSAGE))
return element.text
except:
return None
# 使用Page Object
driver = webdriver.Chrome()
login_page = LoginPage(driver)
login_page.enter_username("test").enter_password("123").click_login()
七、调试技巧
7.1 截图和日志
import logging
from datetime import datetime
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
class SeleniumHelper:
def __init__(self, driver):
self.driver = driver
self.logger = logging.getLogger(__name__)
def take_screenshot(self, name=None):
"""截图并保存"""
if name is None:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
name = f"screenshot_{timestamp}.png"
try:
self.driver.save_screenshot(name)
self.logger.info(f"截图已保存: {name}")
except Exception as e:
self.logger.error(f"截图失败: {e}")
def find_element_with_log(self, by, value, timeout=10):
"""查找元素并记录日志"""
try:
wait = WebDriverWait(self.driver, timeout)
element = wait.until(EC.presence_of_element_located((by, value)))
self.logger.info(f"找到元素: {by}={value}")
return element
except Exception as e:
self.logger.error(f"找不到元素: {by}={value}, 错误: {e}")
self.take_screenshot("element_not_found.png")
raise
7.2 使用Pytest进行测试
# test_example.py
import pytest
from selenium import webdriver
@pytest.fixture(scope="class")
def driver():
"""测试夹具:创建和关闭浏览器"""
driver = webdriver.Chrome()
driver.maximize_window()
yield driver
driver.quit()
class TestBaiduSearch:
"""测试类"""
def test_search(self, driver):
"""测试搜索功能"""
driver.get("https://www.baidu.com")
search_box = driver.find_element(By.ID, "kw")
search_box.send_keys("Selenium自动化测试")
search_button = driver.find_element(By.ID, "su")
search_button.click()
assert "Selenium" in driver.title
def test_navigation(self, driver):
"""测试导航功能"""
driver.get("https://www.baidu.com")
news_link = driver.find_element(By.LINK_TEXT, "新闻")
news_link.click()
assert "新闻" in driver.title
八、常见问题与解决方案
8.1 元素定位问题
# 问题:元素无法定位
# 解决方案:
# 1. 增加等待时间
element = WebDriverWait(driver, 20).until(
EC.presence_of_element_located((By.ID, "element_id"))
)
# 2. 使用不同的定位方式
# 尝试XPath或CSS Selector
# 3. 检查是否在iframe中
driver.switch_to.frame("iframe_name")
# 4. 使用JavaScript查找
element = driver.execute_script("return document.getElementById('element_id');")
8.2 超时问题
# 设置合理的超时时间
driver.set_page_load_timeout(30) # 页面加载超时
driver.set_script_timeout(30) # 脚本执行超时
8.3 内存泄漏问题
# 及时关闭不需要的资源
def safe_quit(driver):
"""安全关闭浏览器"""
try:
driver.quit()
except:
pass
finally:
del driver
九、最佳实践
使用显式等待:避免使用 time.sleep()
异常处理:合理使用 try-except
资源管理:确保浏览器正确关闭
代码复用:使用Page Object模式
配置文件:将配置与代码分离
日志记录:记录关键操作和错误
版本控制:保持驱动与浏览器版本匹配
性能监控:关注内存使用和响应时间
十、学习资源
10.1 官方文档
- Selenium官方文档
- Python Selenium API文档
10.2 进阶学习
- Selenium Grid 分布式测试
- Docker + Selenium 容器化部署
- Jenkins + Selenium 持续集成
- 移动端自动化测试(Appium)
通过这个完整的指南,你可以从基础到高级逐步掌握 Selenium 的使用。实践是最好的学习方式,建议从简单的自动化任务开始,逐步挑战更复杂的场景。