Selenium自动化实战:从小白到大神的进阶之路
今天咱们来聊聊 Selenium自动化测试 那些事儿。
说实话,我第一次接触Selenium的时候也是一脸懵,啥元素定位、显式等待、隐式等待...听得我脑袋瓜子嗡嗡的!
但别怕!跟着我一步步来,保证你也能玩转Selenium!
一、精准元素定位技巧
元素定位图片
定位元素就像在人山人海中找到你的好朋友,得有独特的特征才行!
最常用的定位方法有这几种:
# 导入必要的库
from selenium import webdriver
from selenium.webdriver.common.by import By
# 初始化浏览器驱动
driver = webdriver.Chrome()
driver.get("https://www.example.com")
# 1. ID定位(最靠谱的方式,就像身份证号,独一无二)
username_input = driver.find_element(By.ID, "username")
# 2. NAME定位(常用于表单元素)
password_input = driver.find_element(By.NAME, "password")
# 3. CLASS_NAME定位(适合样式相同的元素)
buttons = driver.find_elements(By.CLASS_NAME, "btn-primary")
# 4. XPATH定位(最强大但也最复杂,就像给地址导航)
login_button = driver.find_element(By.XPATH, "//button[@type='submit' and contains(text(), '登录')]")
# 5. CSS选择器(前端开发者的最爱,简洁高效)
forgot_password = driver.find_element(By.CSS_SELECTOR, ".forgot-password a")
小技巧: 优先使用ID、NAME这种稳定的属性,实在不行再用XPATH或CSS选择器。
踩坑警告: 有些网站的元素ID或CLASS是动态生成的(比如id="item_7a2b3c"),每次刷新都变,这时候就得找更稳定的特征!
二、智能等待机制解析
等待机制图片
网页加载需要时间,别着急,学会"等待"!
不会等待的自动化脚本 = 定时炸弹! 随时可能因为元素还没加载出来就崩溃!
三种等待方式,你必须掌握:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# 1. 强制等待(最简单粗暴,但效率最低)
time.sleep(3) # 无脑等3秒,不管元素是否已经出现
# 2. 隐式等待(全局设置,影响所有find_element操作)
driver.implicitly_wait(10) # 最多等10秒,元素出现就继续
# 3. 显式等待(最智能,只针对特定元素等待)
wait = WebDriverWait(driver, 10) # 创建等待对象,超时时间10秒
login_button = wait.until(EC.element_to_be_clickable((By.ID, "login")))
# 等待直到ID为login的按钮可点击,最多等10秒
实战建议: 显式等待是最佳选择!可以精确控制等待条件,比如等元素可见、可点击、文本包含特定内容等。
等待条件花式玩法:
# 等待元素可见
wait.until(EC.visibility_of_element_located((By.ID, "result")))
# 等待元素不可见(适合等待加载动画消失)
wait.until(EC.invisibility_of_element_located((By.CLASS_NAME, "loading")))
# 等待页面标题包含特定文本
wait.until(EC.title_contains("登录成功"))
# 等待特定文本出现在页面中
wait.until(EC.text_to_be_present_in_element((By.ID, "message"), "操作成功"))
三、复杂用户交互模拟
用户交互图片
不只是点点点,Selenium能模拟各种骚操作!
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
# 基本操作:点击、输入、清除
button = driver.find_element(By.ID, "submit")
button.click()
input_field = driver.find_element(By.NAME, "search")
input_field.clear() # 清除已有内容
input_field.send_keys("Selenium自动化") # 输入文本
input_field.send_keys(Keys.ENTER) # 按回车键
# 高级操作:鼠标悬停、拖拽、右键点击
actions = ActionChains(driver)
# 鼠标悬停(展开下拉菜单)
menu = driver.find_element(By.CLASS_NAME, "dropdown")
actions.move_to_element(menu).perform()
# 拖拽操作(常用于滑块验证码)
source = driver.find_element(By.ID, "draggable")
target = driver.find_element(By.ID, "droppable")
actions.drag_and_drop(source, target).perform()
# 模拟组合键(Ctrl+A全选)
actions.key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()
# 处理弹窗
alert = driver.switch_to.alert
print(alert.text) # 获取弹窗文本
alert.accept() # 点击"确定"
# alert.dismiss() # 点击"取消"
# alert.send_keys("输入内容") # 在提示框中输入
处理iframe嵌套页面:
# 切换到iframe内部(很多网站的富文本编辑器都在iframe中)
iframe = driver.find_element(By.ID, "editor-frame")
driver.switch_to.frame(iframe)
# 在iframe中操作元素
editor = driver.find_element(By.CLASS_NAME, "editor")
editor.send_keys("这是在iframe中输入的内容")
# 切回主文档
driver.switch_to.default_content()
文件上传小技巧: 直接给input[type="file"]元素发送文件路径,不需要点击浏览按钮!
file_input = driver.find_element(By.ID, "upload")
file_input.send_keys("C:\Users\YourName\Pictures\test.jpg")
四、多浏览器兼容方案
多浏览器图片
一套代码,多浏览器运行,这才是真正的自动化!
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.firefox.service import Service as FirefoxService
from selenium.webdriver.edge.service import Service as EdgeService
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager
# 自动下载并配置对应的驱动程序
def get_driver(browser_name):
browser_name = browser_name.lower()
if browser_name == "chrome":
service = ChromeService(ChromeDriverManager().install())
return webdriver.Chrome(service=service)
elif browser_name == "firefox":
service = FirefoxService(GeckoDriverManager().install())
return webdriver.Firefox(service=service)
elif browser_name == "edge":
service = EdgeService(EdgeChromiumDriverManager().install())
return webdriver.Edge(service=service)
else:
raise ValueError(f"不支持的浏览器: {browser_name}")
# 使用方式
driver = get_driver("chrome") # 可以轻松切换为 "firefox" 或 "edge"
无头模式(Headless): 浏览器在后台运行,不显示界面,适合服务器环境!
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument("--headless") # 启用无头模式
chrome_options.add_argument("--disable-gpu") # 某些系统需要
chrome_options.add_argument("--window-size=1920,1080") # 设置窗口大小
driver = webdriver.Chrome(options=chrome_options)
跨浏览器兼容性提示: 不同浏览器对CSS选择器和JavaScript的支持可能有差异,测试时最好覆盖多个主流浏览器。
五、测试框架集成秘籍
测试框架图片
单打独斗不如组团作战,Selenium + 测试框架才是王道!
与Pytest集成
import pytest
from selenium import webdriver
# 使用fixture在测试前后自动处理driver的创建和关闭
@pytest.fixture
def driver():
# 测试前创建driver
driver = webdriver.Chrome()
driver.maximize_window()
yield driver # 返回driver给测试函数使用
# 测试后关闭driver
driver.quit()
# 测试登录功能
def test_login(driver):
driver.get("https://example.com/login")
# 输入用户名密码
driver.find_element(By.ID, "username").send_keys("testuser")
driver.find_element(By.ID, "password").send_keys("password123")
driver.find_element(By.ID, "login-button").click()
# 使用断言验证登录成功
wait = WebDriverWait(driver, 10)
welcome_message = wait.until(EC.visibility_of_element_located((By.ID, "welcome")))
assert "欢迎回来" in welcome_message.text
页面对象模式(POM): 把页面操作封装成类,让测试代码更清晰!
# 登录页面类
class LoginPage:
def __init__(self, driver):
self.driver = driver
self.username_input = (By.ID, "username")
self.password_input = (By.ID, "password")
self.login_button = (By.ID, "login-button")
def navigate(self):
self.driver.get("https://example.com/login")
return self
def login(self, username, password):
self.driver.find_element(*self.username_input).send_keys(username)
self.driver.find_element(*self.password_input).send_keys(password)
self.driver.find_element(*self.login_button).click()
return HomePage(self.driver) # 登录成功后返回首页对象
# 首页类
class HomePage:
def __init__(self, driver):
self.driver = driver
self.welcome_message = (By.ID, "welcome")
def get_welcome_text(self):
wait = WebDriverWait(self.driver, 10)
element = wait.until(EC.visibility_of_element_located(self.welcome_message))
return element.text
# 使用POM的测试代码
def test_login_with_pom(driver):
home_page = LoginPage(driver).navigate().login("testuser", "password123")
assert "欢迎回来" in home_page.get_welcome_text()
自动截图和日志记录: 测试失败时自动保存证据,排查问题事半功倍!
import logging
import os
from datetime import datetime
# 设置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# 失败时截图的函数
def take_screenshot(driver, name):
os.makedirs("screenshots", exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
screenshot_path = f"screenshots/{name}_{timestamp}.png"
driver.save_screenshot(screenshot_path)
logger.info(f"截图保存在: {screenshot_path}")
return screenshot_path
# 在pytest中使用
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
if report.when == "call" and report.failed:
driver = item.funcargs.get("driver")
if driver:
take_screenshot(driver, f"failure_{item.name}")
实战完整示例:自动化登录并提取数据
整合所有技巧,完成一个真实场景的自动化脚本!
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
import pandas as pd
import time
import logging
# 设置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class WebScraper:
def __init__(self, headless=False):
options = webdriver.ChromeOptions()
if headless:
options.add_argument("--headless")
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1920,1080")
service = Service()
self.driver = webdriver.Chrome(service=service, options=options)
self.wait = WebDriverWait(self.driver, 10)
logger.info("浏览器初始化完成")
def login(self, url, username, password):
try:
logger.info(f"正在访问: {url}")
self.driver.get(url)
# 等待登录表单加载
username_input = self.wait.until(EC.presence_of_element_located((By.ID, "username")))
password_input = self.driver.find_element(By.ID, "password")
login_button = self.driver.find_element(By.XPATH, "//button[contains(text(), '登录')]")
# 输入登录信息
username_input.send_keys(username)
password_input.send_keys(password)
login_button.click()
# 验证登录成功
self.wait.until(EC.url_contains("dashboard"))
logger.info("登录成功!")
return True
except TimeoutException:
logger.error("登录失败: 页面加载超时")
self.driver.save_screenshot("login_error.png")
return False
except Exception as e:
logger.error(f"登录过程中出错: {str(e)}")
self.driver.save_screenshot("login_error.png")
return False
def extract_table_data(self, table_selector):
try:
# 等待表格加载
table = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, table_selector)))
# 提取表头
headers = []
header_cells = table.find_elements(By.CSS_SELECTOR, "thead th")
for cell in header_cells:
headers.append(cell.text.strip())
# 提取数据行
rows = []
data_rows = table.find_elements(By.CSS_SELECTOR, "tbody tr")
for row in data_rows:
cells = row.find_elements(By.TAG_NAME, "td")
row_data = [cell.text.strip() for cell in cells]
rows.append(row_data)
# 创建DataFrame
df = pd.DataFrame(rows, columns=headers)
logger.info(f"成功提取{len(rows)}行数据")
return df
except Exception as e:
logger.error(f"提取表格数据时出错: {str(e)}")
self.driver.save_screenshot("table_extract_error.png")
return None
def export_to_excel(self, df, filename):
try:
df.to_excel(filename, index=False)
logger.info(f"数据已导出到: {filename}")
return True
except Exception as e:
logger.error(f"导出Excel时出错: {str(e)}")
return False
def close(self):
if self.driver:
self.driver.quit()
logger.info("浏览器已关闭")
# 使用示例
if __name__ == "__main__":
scraper = WebScraper(headless=False)
try:
if scraper.login("https://example.com/login", "your_username", "your_password"):
# 等待页面加载完成
time.sleep(2)
# 导航到数据页面
scraper.driver.get("https://example.com/data")
# 提取表格数据
data = scraper.extract_table_data("#data-table")
if data is not None:
# 导出到Excel
scraper.export_to_excel(data, "extracted_data.xlsx")
finally:
scraper.close()
总结一下: Selenium自动化测试不难,关键是掌握这几点:
- 精准定位元素 - 找对人才能办对事
- 智能等待机制 - 别急,给网页一点加载时间
- 模拟复杂交互 - 不只是点点点,还能拖拽、悬停
- 多浏览器兼容 - 一套代码,到处运行
- 测试框架集成 - 规范化你的测试,事半功倍
掌握了这些,你就从Selenium小白变成大神啦!有问题随时交流,一起进步!
本文使用 markdown.com.cn 排版