目录
Selenium 简介
主要特点
核心组件详解
1. WebDriver
2. Selenium IDE
3. Selenium Grid
Python 环境下的详细配置
安装过程
基础配置示例
完整操作示例及解析
元素定位方法详解
1. ID 定位
2. 类名定位
3. CSS 选择器定位
4. XPath 定位
5. 链接文本定位
6. 标签名定位
7. Name属性定位
最佳实践建议
等待机制深度解析
1. 强制等待(不推荐)
2. 隐式等待(全局设置)
3. 显式等待(推荐)
高级应用场景
1. 文件上传处理
2. 下拉选择框操作
3. 弹窗处理
4. 浏览器多窗口/标签页管理
性能优化与最佳实践
常见问题解决方案
测试框架集成
与pytest集成示例
生成测试报告
学习资源推荐
Selenium 是一个功能强大的开源自动化测试框架,主要用于Web应用程序的自动化测试。它通过模拟真实用户行为来测试Web应用的交互性和功能性,支持跨浏览器、跨平台测试,是当前最流行的Web自动化测试工具之一。
WebDriver 是 Selenium 的核心组件,通过浏览器特定的驱动程序直接与浏览器通信:
这些驱动程序作为浏览器和Selenium脚本之间的桥梁,遵循W3C WebDriver标准协议。
Selenium IDE (Integrated Development Environment) 是一个浏览器扩展,提供:
适用于快速创建简单的测试用例和原型验证。
Selenium Grid 是一个分布式测试工具,支持:
典型应用场景包括:
安装 Selenium 库:
pip install selenium
下载对应浏览器的 WebDriver:
配置方式:
from selenium import webdriver
# 方法1:使用环境变量配置
driver = webdriver.Chrome() # 自动从PATH查找chromedriver
# 方法2:指定驱动程序路径
driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
# 方法3:使用Service对象(推荐Selenium 4+)
from selenium.webdriver.chrome.service import Service
service = Service('/path/to/chromedriver')
driver = webdriver.Chrome(service=service)
下面是一个详细的百度搜索自动化测试示例,包含完整的异常处理和等待机制:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
def baidu_search(keyword):
# 初始化浏览器实例
driver = webdriver.Chrome()
try:
# 打开百度首页
driver.get("https://www.baidu.com")
print(f"当前页面标题: {driver.title}")
# 验证是否成功加载百度首页
assert "百度一下" in driver.title
# 定位搜索框元素
search_box = driver.find_element(By.ID, "kw")
# 输入搜索关键词
search_box.clear() # 先清空可能存在的默认内容
search_box.send_keys(keyword)
# 模拟按下回车键
search_box.send_keys(Keys.RETURN)
# 等待搜索结果加载完成
wait = WebDriverWait(driver, 10)
results = wait.until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.result.c-container"))
)
# 输出前5条搜索结果
print("\n搜索结果前5条:")
for i, result in enumerate(results[:5], 1):
title = result.find_element(By.TAG_NAME, "h3").text
link = result.find_element(By.TAG_NAME, "a").get_attribute("href")
print(f"{i}. {title} ({link})")
# 截图保存搜索结果
driver.save_screenshot("search_results.png")
# 短暂停留以便观察
time.sleep(2)
except Exception as e:
print(f"测试执行失败: {str(e)}")
driver.save_screenshot("error.png")
finally:
# 确保浏览器关闭
driver.quit()
if __name__ == "__main__":
baidu_search("Selenium自动化测试")
Selenium 提供多种元素定位策略,适用于不同场景:
element = driver.find_element(By.ID, "username")
适用场景:元素有唯一ID时最快速可靠的定位方式
elements = driver.find_elements(By.CLASS_NAME, "btn-primary")
注意:一个元素可能有多个类名,类名通常不唯一
element = driver.find_element(By.CSS_SELECTOR, "div.content > input[name='email']")
优势:
element = driver.find_element(By.XPATH, "//div[@class='container']//a[contains(text(),'登录')]")
适用场景:
element = driver.find_element(By.LINK_TEXT, "用户协议")
element = driver.find_element(By.PARTIAL_LINK_TEXT, "协议")
仅适用于标签,精确或模糊匹配链接文本
buttons = driver.find_elements(By.TAG_NAME, "button")
通常用于获取同一类型的多个元素
element = driver.find_element(By.NAME, "password")
适用于表单元素的标准定位方式
定位策略优先级:
元素定位技巧:
# 组合定位策略
driver.find_element(By.XPATH, "//input[@id='username' and @class='form-control']")
# 相对定位
form = driver.find_element(By.ID, "login-form")
username = form.find_element(By.NAME, "username")
# 等待元素可交互
element = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "submit-btn"))
)
常见问题解决:
driver.execute_script("arguments[0].scrollIntoView();", element)
driver.switch_to.frame("iframe-name")
time.sleep(5) # 固定等待5秒
问题:无论元素是否已加载完成都会等待,降低测试效率
driver.implicitly_wait(10) # 全局超时10秒
特点:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "dynamic-element"))
)
常用等待条件:
visibility_of_element_located
- 元素可见element_to_be_clickable
- 元素可点击text_to_be_present_in_element
- 元素包含特定文本invisibility_of_element_located
- 元素不可见frame_to_be_available_and_switch_to_it
- iframe可用# 标准文件上传控件
upload = driver.find_element(By.ID, "file-upload")
upload.send_keys("/absolute/path/to/file.txt")
# 隐藏的文件输入框(需JavaScript处理)
driver.execute_script("document.getElementById('hidden-file-input').style.display='block';")
hidden_upload = driver.find_element(By.ID, "hidden-file-input")
hidden_upload.send_keys("/path/to/file.pdf")
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element(By.ID, "country"))
# 选择方式
select.select_by_visible_text("中国") # 按显示文本
select.select_by_value("CN") # 按value属性
select.select_by_index(1) # 按选项索引
# 获取所有选项
options = select.options
for option in options:
print(option.text, option.get_attribute("value"))
# 多选下拉框操作
multi_select = Select(driver.find_element(By.NAME, "languages"))
multi_select.deselect_all() # 取消所有选择
multi_select.select_by_value("en")
multi_select.select_by_value("zh")
# 等待并处理alert
WebDriverWait(driver, 5).until(EC.alert_is_present())
alert = driver.switch_to.alert
print(alert.text) # 获取弹窗文本
alert.accept() # 确认
# alert.dismiss() # 取消
# 带输入的提示框
prompt = driver.switch_to.alert
prompt.send_keys("输入内容")
prompt.accept()
# 模态对话框处理
modal = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.ID, "modal-dialog"))
)
modal.find_element(By.CLASS_NAME, "confirm-btn").click()
# 获取当前窗口句柄
main_window = driver.current_window_handle
# 点击打开新窗口的链接
driver.find_element(By.LINK_TEXT, "新窗口打开").click()
# 切换到新窗口
WebDriverWait(driver, 5).until(lambda d: len(d.window_handles) > 1)
for handle in driver.window_handles:
if handle != main_window:
driver.switch_to.window(handle)
break
# 在新窗口操作
print("新窗口标题:", driver.title)
# 关闭新窗口并切回主窗口
driver.close()
driver.switch_to.window(main_window)
定位优化:
# 避免在循环中重复查找
# 不推荐
for i in range(5):
driver.find_element(By.ID, "btn").click()
# 推荐
button = driver.find_element(By.ID, "btn")
for i in range(5):
button.click()
# 使用find_elements批量获取
items = driver.find_elements(By.CLASS_NAME, "list-item")
等待策略优化:
# 设置合理的全局隐式等待
driver.implicitly_wait(3) # 不要设置过长
# 关键操作使用显式等待
WebDriverWait(driver, 10).until(
EC.invisibility_of_element_located((By.ID, "loading"))
)
浏览器配置优化:
# Chrome选项优化
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless") # 无头模式
options.add_argument("--disable-gpu") # 禁用GPU加速
options.add_argument("--window-size=1920,1080") # 设置窗口大小
driver = webdriver.Chrome(options=options)
测试数据管理:
元素点击不生效:
# 方案1:使用JavaScript点击
driver.execute_script("arguments[0].click();", element)
# 方案2:先滚动到元素可见
driver.execute_script("arguments[0].scrollIntoView(true);", element)
element.click()
# 方案3:使用Actions类模拟点击
from selenium.webdriver.common.action_chains import ActionChains
ActionChains(driver).move_to_element(element).click().perform()
处理动态元素:
# 使用XPath函数处理动态属性
element = driver.find_element(By.XPATH, "//div[starts-with(@id, 'prefix_')]")
# 使用CSS选择器匹配部分属性
element = driver.find_element(By.CSS_SELECTOR, "div[id^='prefix']")
# 等待元素属性变化
WebDriverWait(driver, 10).until(
lambda d: d.find_element(By.ID, "status").get_attribute("class") == "completed"
)
绕过同源策略限制:
# 处理跨域iframe
driver.switch_to.frame(driver.find_element(By.TAG_NAME, "iframe"))
# 操作iframe内容
driver.find_element(By.ID, "iframe-content").click()
# 返回主文档
driver.switch_to.default_content()
import pytest
from selenium import webdriver
@pytest.fixture(scope="module")
def browser():
# 测试前初始化
driver = webdriver.Chrome()
driver.implicitly_wait(5)
yield driver
# 测试后清理
driver.quit()
@pytest.mark.parametrize("search_keyword,expected", [
("Python", "Python"),
("Selenium", "Selenium"),
("自动化测试", "自动化测试")
])
def test_baidu_search(browser, search_keyword, expected):
browser.get("https://www.baidu.com")
browser.find_element(By.ID, "kw").send_keys(search_keyword + Keys.RETURN)
assert expected in browser.title
使用pytest-html插件生成美观的HTML报告:
pytest --html=report.html
官方文档:
进阶学习:
社区资源:
持续集成: