
1. 项目概述为什么选择PythonSelenium做Web自动化如果你是一名测试工程师、开发人员或者是对提升工作效率有追求的互联网从业者那么“自动化测试”这个词你一定不陌生。而Web自动化作为自动化测试中最常见、应用最广泛的领域之一其核心目标就是让机器代替人工去模拟用户在浏览器中的操作比如点击、输入、滚动、验证页面元素等。这听起来简单但当你面对成百上千个回归测试用例或者需要在凌晨三点验证一个上线功能时手动测试的效率和可靠性就显得捉襟见肘了。在众多Web自动化工具中Selenium无疑是王者级别的存在。它是一个开源的、支持多浏览器、多语言的Web应用测试框架。而Python以其简洁的语法、丰富的生态库和强大的社区支持成为了与Selenium结合最紧密、也最受开发者欢迎的语言之一。PythonSelenium的组合就像给测试工作装上了一双“机械臂”既能精准执行重复性任务又能通过灵活的脚本应对复杂的测试逻辑。我从业十多年从早期的QTP到现在的Selenium亲眼见证了这套组合如何从一个“可选方案”变成测试团队的“基础设施”。它解决的不仅仅是“测试”问题更是释放人力、提升交付质量、实现持续集成/持续交付CI/CD的关键一环。那么这个组合适合谁呢首先当然是测试工程师这是你的核心技能树。其次是开发人员尤其是全栈或后端开发掌握UI自动化能让你在自测、联调时更加游刃有余。最后对于任何需要与网页进行大量、规律性交互的岗位比如数据采集需合规、运营监控等这套技术也能提供强大的支持。接下来我将带你从零开始深入这套技术的每一个核心环节不仅告诉你“怎么做”更会分享我踩过的坑和积累的实战技巧。2. 环境搭建与核心工具选型解析工欲善其事必先利其器。搭建一个稳定、高效的自动化测试环境是后续所有工作的基石。这一步看似简单却暗藏玄机很多新手都在这里栽了跟头。2.1 Python环境版本管理与虚拟环境隔离首先解决Python。我强烈建议你使用Python 3.7及以上版本因为很多新的库和Selenium的特性对老版本支持不佳。直接从Python官网下载安装包是最稳妥的方式。安装时务必勾选“Add Python to PATH”这样你才能在命令行中直接使用python和pip命令。注意很多教程会推荐使用Anaconda但对于纯Web自动化测试来说它过于庞大。标准Python安装器pip足以满足需求保持环境轻量。安装完成后第一件要做的事不是装Selenium而是建立虚拟环境。这是一个至关重要的好习惯。虚拟环境可以为每个项目创建独立的Python包安装空间避免不同项目间的依赖冲突。想象一下项目A需要Selenium 3.14项目B需要Selenium 4.0如果没有隔离你将陷入无尽的版本地狱。创建虚拟环境非常简单。打开命令行Windows用CMD或PowerShellMac/Linux用Terminal进入你的项目目录然后执行# 创建名为 venv 的虚拟环境 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # Mac/Linux: source venv/bin/activate激活后命令行的前缀会变成(venv)表示你已进入该虚拟环境。之后所有pip install操作都只影响这个环境。2.2 Selenium库安装与浏览器驱动管理环境准备好后安装Selenium库就是一行命令的事pip install selenium这通常会安装最新稳定版的Selenium目前是4.x系列。Selenium 4相较于3.x有重大改进比如相对定位器、新的窗口/标签页管理等建议直接使用4.x。接下来是重中之重浏览器驱动。Selenium本身只是一个发出指令的“大脑”它需要对应的“手”驱动来操作具体的浏览器。以最常用的Chrome浏览器为例你需要下载与你的Chrome浏览器版本匹配的chromedriver。查看Chrome版本在浏览器地址栏输入chrome://settings/help查看版本号。下载对应驱动访问ChromeDriver官网或国内镜像站下载对应版本主版本号一致即可的驱动。配置驱动路径有三种常用方法方法一推荐灵活将下载的chromedriver.exeWindows或chromedriverMac/Linux放在项目目录下或在代码中指定路径。方法二系统级将驱动文件放在系统PATH环境变量包含的目录中如/usr/local/binMac/Linux或C:\WindowsWindows。方法三自动化管理使用webdriver-manager库它可以自动下载和匹配驱动。安装pip install webdriver-manager在代码中调用即可非常适合CI/CD环境。我个人的经验是在本地开发时使用方法一清晰明了在团队共享或服务器上运行时使用方法三省去手动管理的麻烦。对于Firefoxgeckodriver和Edgemsedgedriver逻辑完全一样。2.3 IDE与辅助工具提升脚本开发效率写Python脚本一个好用的IDE能事半功倍。VS Code和PyCharm是两大主流选择。VS Code轻量、免费、插件生态极其丰富。你需要安装Python扩展和Pylance用于智能提示。它的调试功能对排查自动化脚本问题非常友好。PyCharm专业级Python IDE功能更全面特别是其专业版对Web开发和支持有深度集成。社区版也足够用于自动化测试。除了IDE还有一些辅助工具能极大提升效率Selenium IDE一个浏览器插件可以录制你在浏览器中的操作并生成测试脚本支持Python。它不适合构建复杂、可维护的测试套件但非常适合用于快速生成元素定位代码或者给新手做演示。你可以通过录制点击某个按钮然后查看它生成的定位器如XPath或CSS Selector再复制到你的正式脚本中。浏览器开发者工具F12打开Elements标签页和Console标签页是你最好的朋友。用于查看页面HTML结构、验证XPath/CSS选择器、执行JavaScript片段。3. Selenium核心API与元素定位实战环境搭好我们就进入了自动化测试的核心操控浏览器。Selenium WebDriver提供了一套丰富的API而这一切的起点就是与页面上的元素进行交互。元素定位是Web自动化的基石也是新手遇到问题最多的地方。3.1 WebDriver初始化与基础操作让我们从一个最简单的脚本开始它包含了所有核心操作from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys import time # 初始化驱动 - 这里以Chrome为例使用webdriver-manager自动管理 from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.chrome.service import Service service Service(ChromeDriverManager().install()) driver webdriver.Chrome(serviceservice) # 打开网页 driver.get(https://www.baidu.com) print(f页面标题是{driver.title}) # 定位搜索框并输入关键词 search_box driver.find_element(By.ID, kw) # 使用ID定位 search_box.send_keys(Selenium自动化测试) search_box.send_keys(Keys.RETURN) # 模拟回车键 # 等待一下查看结果 time.sleep(3) # 关闭浏览器 driver.quit()这段代码做了以下几件事初始化驱动通过webdriver.Chrome()创建了一个浏览器实例。使用webdriver-manager避免了手动管理驱动版本的麻烦。导航driver.get(url)命令浏览器打开指定URL。定位元素driver.find_element(By.ID, kw)使用元素的ID属性来找到百度搜索框。By类提供了多种定位方式。交互操作send_keys()用于输入文本send_keys(Keys.RETURN)模拟键盘回车。关闭driver.quit()会关闭所有窗口并结束WebDriver会话。务必在脚本最后调用释放资源。实操心得永远使用driver.quit()而不是driver.close()。close()只关闭当前标签页如果只有一个标签页则关闭浏览器但可能不会彻底终止驱动进程导致端口占用等问题。quit()是彻底的清理。3.2 八大元素定位策略详解与选用原则Selenium提供了8种主要的定位策略By类中的属性每种都有其适用场景。定位方式示例 (By.XXX, “值”)优点缺点/注意事项IDBy.ID, “userName”唯一性最好定位速度最快不是所有元素都有IDID可能动态生成NAMEBy.NAME, “password”常用于表单元素比较稳定可能不唯一CLASS_NAMEBy.CLASS_NAME, “btn-primary”适合定位具有相同样式的元素类名经常复用不唯一复合类名需完整匹配TAG_NAMEBy.TAG_NAME, “input”定位某一类标签如所有输入框通常不唯一需结合其他条件筛选LINK_TEXTBy.LINK_TEXT, “登录”精准定位超链接文本文本必须完全匹配文本可能变化PARTIAL_LINK_TEXTBy.PARTIAL_LINK_TEXT, “录”链接文本的部分匹配更灵活可能匹配到多个链接CSS_SELECTORBy.CSS_SELECTOR, “#kw”功能强大语法简洁浏览器原生支持快语法需要学习复杂结构的选择器可能冗长XPATHBy.XPATH, “//input[id‘kw’]”功能最强大可以遍历整个DOM树语法复杂性能相对较差绝对路径脆弱定位策略选用原则我的经验之谈优先级最高ID。如果元素有稳定、唯一的ID毫不犹豫用它。次选CSS Selector。在无ID时CSS Selector通常是首选。它比XPath更快浏览器优化语法更易读且能处理大部分复杂场景。例如By.CSS_SELECTOR, “.login-form input[type‘submit’]”。谨慎使用XPath。XPath非常强大尤其是当需要根据文本、兄弟节点、祖先节点等复杂关系定位时。但应尽量避免使用浏览器开发者工具直接复制的绝对路径XPath如/html/body/div[3]/div[2]/form/span[1]/input这种路径极度脆弱页面结构稍有变动就会失效。应使用相对路径和属性结合的方式如//button[contains(text(), ‘提交’)]或//div[class‘list’]//li[1]。NAME和CLASS_NAME作为辅助在表单等场景下很好用。LINK_TEXT只用于真正的a链接。如何验证定位器在浏览器开发者工具的Console标签中你可以使用$x(“你的xpath”)来测试XPath用$(“你的css”)来测试CSS Selector它们会返回匹配的元素数组。3.3 等待机制解决自动化“翻车”的头号元凶元素定位失败十有八九是因为页面还没加载完。直接操作会抛出NoSuchElementException。因此“等待”是编写健壮自动化脚本的核心。1. 强制等待time.sleep(seconds)最简单粗暴让脚本暂停指定秒数。除非万不得已如等待一个固定时间的动画否则不要用它会无谓地拉长测试时间且无法适应网络或性能波动。2. 隐式等待driver.implicitly_wait(seconds)设置一个全局等待时间。在查找任何元素时如果没立即找到WebDriver会轮询DOM直到超时。它只对find_element系列方法有效。driver.implicitly_wait(10) # 设置隐式等待10秒 element driver.find_element(By.ID, “dynamicElement”)问题它是全局的会影响所有查找操作。对于某些本应快速失败的操作如验证元素不存在不友好。3. 显式等待WebDriverWaitexpected_conditions这是最佳实践必须掌握。它允许你为某个特定条件设置等待条件满足则立即继续超时则抛出异常。它更智能更节省时间。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 等待最多10秒直到ID为‘result’的元素可见 wait WebDriverWait(driver, 10) result_element wait.until(EC.visibility_of_element_located((By.ID, “result”))) # 等待元素可被点击 submit_button wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, “.submit-btn”))) submit_button.click() # 等待页面标题包含特定文字 wait.until(EC.title_contains(“搜索结果”))expected_conditions模块提供了大量预定义条件如元素是否存在、是否可见、是否可点击、文本是否出现等。这是编写稳定脚本的利器。我的等待策略组合在驱动初始化后设置一个较短的隐式等待如5秒作为兜底。在所有关键交互点点击、输入后页面跳转或元素变化使用显式等待来等待特定条件。几乎不使用强制等待。4. 构建可维护的自动化测试框架当你的自动化脚本从一个、两个发展到几十上百个时如果还把所有代码、定位器、测试数据混在一起维护将是一场噩梦。这时你需要一个清晰的框架。框架的目标是高内聚、低耦合、易维护、易扩展。4.1 Page Object Model (POM) 设计模式POM是UI自动化测试的黄金标准。其核心思想是将页面抽象成一个类将页面上的元素定义为类的属性将页面上的操作定义为类的方法。测试用例则通过调用这些页面对象的方法来完成业务流。没有POM的代码面条代码def test_login(): driver.find_element(By.ID, “username”).send_keys(“admin”) driver.find_element(By.ID, “password”).send_keys(“123456”) driver.find_element(By.ID, “submit”).click() assert “欢迎” in driver.page_source使用POM后的代码# pages/login_page.py class LoginPage: def __init__(self, driver): self.driver driver self.username_input (By.ID, “username”) self.password_input (By.ID, “password”) self.submit_button (By.ID, “submit”) self.welcome_msg (By.CSS_SELECTOR, “.welcome”) def enter_username(self, username): self.driver.find_element(*self.username_input).send_keys(username) def enter_password(self, password): self.driver.find_element(*self.password_input).send_keys(password) def click_submit(self): self.driver.find_element(*self.submit_button).click() def get_welcome_text(self): return self.driver.find_element(*self.welcome_msg).text def login(self, username, password): # 业务组合方法 self.enter_username(username) self.enter_password(password) self.click_submit() # tests/test_login.py def test_login(): login_page LoginPage(driver) login_page.login(“admin”, “123456”) assert “欢迎” in login_page.get_welcome_text()POM带来的好处可维护性当登录页面的输入框ID从username变成user时你只需要修改LoginPage类中的一个地方所有测试用例无需改动。可读性测试用例读起来就像自然语言login_page.login(“admin”, “123456”)业务逻辑一目了然。复用性页面对象可以在多个测试用例中被复用。4.2 测试数据、配置与日志管理测试数据分离不要将测试数据用户名、密码、URL硬编码在脚本中。应该使用外部文件来管理如JSON、YAML、Excel或CSV。# config.json { “base_url”: “https://example.com”, “users”: { “admin”: {“username”: “admin”, “password”: “admin123”}, “guest”: {“username”: “guest”, “password”: “guest123”} } } # 在代码中读取 import json with open(‘config.json’, ‘r’) as f: config json.load(f) base_url config[‘base_url’] admin_user config[‘users’][‘admin’]配置文件将浏览器类型、隐式等待时间、截图保存路径等运行时配置也放在外部文件如config.ini或settings.py中。日志记录使用Python内置的logging模块记录测试执行过程。这比单纯用print()强大得多可以设置不同级别DEBUG, INFO, WARNING, ERROR输出到控制台和文件便于事后排查问题。import logging logging.basicConfig(levellogging.INFO, format‘%(asctime)s - %(name)s - %(levelname)s - %(message)s’, handlers[logging.FileHandler(“test.log”), logging.StreamHandler()]) logger logging.getLogger(__name__) logger.info(“开始执行登录测试...”)4.3 测试用例组织与断言使用专业的测试框架来组织用例最主流的是pytest和unittest。我强烈推荐pytest因为它更简洁、功能更强大如Fixture、参数化、插件生态。# test_login.py import pytest from pages.login_page import LoginPage class TestLogin: pytest.fixture(scope“class”) def driver(self): # 初始化驱动整个测试类只执行一次 driver webdriver.Chrome() driver.implicitly_wait(5) yield driver driver.quit() # 测试类结束后退出 pytest.fixture def login_page(self, driver): driver.get(“https://example.com/login”) return LoginPage(driver) def test_login_success(self, login_page): “”“测试正常登录”“” login_page.login(“admin”, “admin123”) # 使用断言验证结果 assert “Dashboard” in login_page.get_title() # 或者使用pytest的断言失败时信息更友好 assert login_page.get_welcome_text() “欢迎回来admin” pytest.mark.parametrize(“username, password, expected_error”, [ (“”, “admin123”, “用户名不能为空”), (“admin”, “”, “密码不能为空”), (“wrong”, “wrong”, “用户名或密码错误”), ]) def test_login_failure(self, login_page, username, password, expected_error): “”“参数化测试多种登录失败场景”“” login_page.login(username, password) assert expected_error in login_page.get_error_message()pytest的fixture提供了强大的setup/teardown机制。pytest.mark.parametrize使得数据驱动测试变得异常简单。断言则用于验证测试结果是否符合预期是测试的灵魂。5. 高级技巧与常见问题实战排查掌握了基础框架我们来看看那些让自动化脚本更稳定、更智能的高级技巧以及如何解决那些令人头疼的常见问题。5.1 处理弹窗、iframe与多窗口/标签页JavaScript弹窗Alert/Confirm/Promptfrom selenium.webdriver.common.alert import Alert # 触发一个alert driver.find_element(By.ID, “trigger-alert”).click() # 切换到alert alert Alert(driver) print(alert.text) # 获取弹窗文本 alert.accept() # 点击“确定” # alert.dismiss() # 点击“取消” # alert.send_keys(“输入文本”) # 针对Prompt弹窗输入iframe内嵌框架操作iframe内的元素前必须先切换到对应的iframe。# 通过ID或Name切换 driver.switch_to.frame(“iframe_id”) # 通过索引切换从0开始 driver.switch_to.frame(0) # 通过WebElement切换 iframe_element driver.find_element(By.TAG_NAME, “iframe”) driver.switch_to.frame(iframe_element) # 操作iframe内的元素 driver.find_element(By.ID, “inside_element”).click() # 操作完成后切回主文档 driver.switch_to.default_content() # 或者切回上一级iframe driver.switch_to.parent_frame()多窗口/标签页# 获取当前窗口句柄 main_window driver.current_window_handle # 点击一个打开新窗口的链接 driver.find_element(By.LINK_TEXT, “新窗口”).click() # 获取所有窗口句柄 all_windows driver.window_handles new_window [window for window in all_windows if window ! main_window][0] # 切换到新窗口 driver.switch_to.window(new_window) # 在新窗口操作 print(driver.title) # 操作完后可以关闭新窗口并切回主窗口 driver.close() driver.switch_to.window(main_window)5.2 文件上传、下拉框与复杂鼠标/键盘操作文件上传对于input type“file”元素直接使用send_keys()传入文件绝对路径即可。upload_element driver.find_element(By.ID, “file-upload”) upload_element.send_keys(“/Users/yourname/Desktop/test.png”)对于非input类型的上传如需要点击按钮弹出系统对话框则比较棘手通常需要借助AutoIT、PyAutoGUI等桌面自动化工具但这会引入依赖且不够稳定。优先建议让开发改为input类型。下拉选择框Select使用Select类来处理select标签。from selenium.webdriver.support.ui import Select select_element driver.find_element(By.ID, “country”) select Select(select_element) # 通过可见文本选择 select.select_by_visible_text(“中国”) # 通过value属性选择 select.select_by_value(“CN”) # 通过索引选择从0开始 select.select_by_index(1) # 获取所有选项 all_options select.options for option in all_options: print(option.text)复杂鼠标操作ActionChains用于模拟鼠标悬停、拖放、右键点击等。from selenium.webdriver.common.action_chains import ActionChains menu driver.find_element(By.ID, “menu”) submenu driver.find_element(By.ID, “submenu”) # 鼠标悬停 actions ActionChains(driver) actions.move_to_element(menu).perform() # 此时子菜单应显示再点击子菜单 submenu.click() # 拖放操作 source driver.find_element(By.ID, “draggable”) target driver.find_element(By.ID, “droppable”) actions.drag_and_drop(source, target).perform()5.3 常见问题排查与反爬应对策略问题1元素定位到了但点击/输入没反应可能原因1元素不可交互。元素可能被遮挡如弹窗、遮罩层、不可见display: none或visibility: hidden、或处于禁用状态disabled属性。使用EC.element_to_be_clickable进行显式等待可以部分解决。可能原因2需要滚动到视图。如果元素不在当前可视区域内Selenium可能无法与之交互。可以先滚动到该元素element driver.find_element(By.ID, “target”) driver.execute_script(“arguments[0].scrollIntoView(true);”, element) element.click()可能原因3需要等待元素稳定。有时元素刚出现时状态不稳定。可以尝试短时间强制等待time.sleep(0.5)或使用更复杂的等待条件。问题2脚本在本地运行正常在服务器/CI上失败可能原因1浏览器驱动版本不匹配。CI服务器上的浏览器版本可能与本地不同。使用webdriver-manager可以自动解决。可能原因2无头模式或分辨率差异。在服务器上通常以无头模式运行不显示UI或屏幕分辨率不同可能导致元素定位或渲染差异。在初始化驱动时添加相应选项from selenium.webdriver.chrome.options import Options options Options() options.add_argument(“--headless”) # 无头模式 options.add_argument(“--window-size1920,1080”) # 设置窗口大小 options.add_argument(“--disable-gpu”) # 禁用GPU加速在某些环境下需要 driver webdriver.Chrome(optionsoptions)可能原因3环境依赖缺失。确保服务器上安装了必要的库如Chrome浏览器本身。问题3网站检测到Selenium并屏蔽一些网站会通过检测浏览器特征如navigator.webdriver属性来识别自动化脚本。应对策略包括使用undetected-chromedriver这是一个第三方库专门用于规避检测。pip install undetected-chromedriver用法类似。添加实验性选项可能失效options.add_experimental_option(“excludeSwitches”, [“enable-automation”]) options.add_experimental_option(‘useAutomationExtension’, False) options.add_argument(‘--disable-blink-featuresAutomationControlled’)修改CDPChrome DevTools ProtocolSelenium 4支持直接执行CDP命令。driver.execute_cdp_cmd(‘Page.addScriptToEvaluateOnNewDocument’, { ‘source’: ‘Object.defineProperty(navigator, “webdriver”, {get: () undefined})’ })注意这些方法可能随着网站反爬策略升级而失效且需遵守网站的使用条款。问题4如何处理动态加载的内容Ajax这是现代Web应用单页应用SPA的常态。核心是等待而不是time.sleep。等待某个特定元素出现presence_of_element_located。等待某个元素可见visibility_of_element_located。等待旧元素消失invisibility_of_element_located如表单提交后的加载动画。等待页面某个属性达到特定状态自定义等待条件。# 自定义等待条件等待元素包含特定文本 def text_to_be_present_in_element(locator, text): def _predicate(driver): try: element_text driver.find_element(*locator).text return text in element_text except StaleElementReferenceException: return False return _predicate wait.until(text_to_be_present_in_element((By.ID, “status”), “加载完成”))6. 集成与进阶报告生成与CI/CD流水线一个成熟的自动化测试体系不仅要能运行还要能产出直观的结果并能集成到开发流程中。6.1 测试报告生成pytest自身可以通过-v参数输出详细结果但更专业的报告需要插件。pytest-html生成简洁的HTML报告。pip install pytest-html运行pytest --htmlreport.html。Allure功能强大、美观的测试报告框架。需要先安装Java和Allure命令行工具再安装pytest-allure插件。它可以展示测试步骤、截图、历史趋势等是团队展示测试成果的利器。生成报告后一个重要的实践是失败截图。在pytest中可以通过钩子函数hook或在fixture的teardown中实现import pytest from datetime import datetime pytest.hookimpl(tryfirstTrue, hookwrapperTrue) def pytest_runtest_makereport(item, call): outcome yield report outcome.get_result() if report.when “call” and report.failed: # 仅在测试用例执行失败时截图 driver item.funcargs.get(‘driver’) # 假设driver是fixture if driver: timestamp datetime.now().strftime(“%Y%m%d_%H%M%S”) screenshot_path f”./screenshots/failure_{item.name}_{timestamp}.png” driver.save_screenshot(screenshot_path) # 可以将截图路径附加到报告 report.extra [pytest_html.extras.image(screenshot_path, ‘失败截图’)]6.2 集成到CI/CD以Jenkins为例持续集成/持续交付是自动化测试价值最大化的地方。每次代码提交都自动触发测试快速反馈。准备测试脚本和依赖在项目根目录创建requirements.txt文件列出所有依赖selenium,pytest,webdriver-manager等。编写JenkinsfilePipeline脚本pipeline { agent any stages { stage(‘Checkout’) { steps { git ‘https://your-git-repo.git’ } } stage(‘Setup Environment’) { steps { sh ‘python -m venv venv’ sh ‘. venv/bin/activate pip install -r requirements.txt’ } } stage(‘Run Tests’) { steps { script { // 激活虚拟环境并运行测试生成报告 sh ‘’’ . venv/bin/activate pytest --htmlreport.html --self-contained-html ‘’’ } } } stage(‘Archive Report’) { steps { // 将HTML报告归档供Jenkins展示 publishHTML(target: [ reportName: ‘Pytest HTML Report’, reportDir: ‘.’, reportFiles: ‘report.html’, keepAll: true ]) } } } post { always { // 无论成功失败都清理或发送通知 cleanWs() } } }配置Jenkins Job创建一个Pipeline类型的Job指向你的仓库和Jenkinsfile。这样每次代码推送Jenkins就会自动拉取代码、安装依赖、运行测试并生成报告。6.3 性能与稳定性优化建议并行测试使用pytest-xdist插件可以并行运行测试用例大幅缩短测试总时间。pytest -n autoauto表示使用所有CPU核心。使用更快的驱动对于Chrome可以尝试chromedriver的--disable-dev-shm-usage和--no-sandbox选项尤其在Docker容器中有时能提升稳定性。减少不必要的等待合理使用显式等待杜绝随意sleep。分析测试用例将独立的模块拆分便于并行和重试。失败重试机制使用pytest-rerunfailures插件对不稳定的测试用例进行自动重试。pytest --reruns 2失败后重试2次。资源清理确保每个测试用例或测试类都有良好的setup和teardown及时关闭浏览器、清理临时数据避免测试间相互影响。走到这一步你的Web自动化测试已经从一个简单的脚本演进为一个工程化、可集成、可维护的测试解决方案。它能真正为你的团队和项目带来质量保障和效率提升。记住自动化测试不是一劳永逸的随着产品迭代测试用例和页面对象也需要持续维护和更新。保持代码的整洁和良好的设计会让这份维护工作轻松很多。