
1. 项目概述为什么我们需要一份中文Selenium-Python手册如果你是一名测试工程师、开发人员或者任何需要与网页交互的自动化脚本编写者那么“Selenium”这个名字对你来说一定不陌生。它是一个强大的浏览器自动化工具而Python则是其最受欢迎的“搭档”之一。市面上关于Selenium和Python的资料浩如烟海但当你真正上手时可能会发现一个尴尬的局面官方文档是英文的很多教程要么过于零散不成体系要么版本老旧跟不上Selenium的快速迭代。你需要的不是一个简单的命令列表而是一个能告诉你“为什么这么做”、“踩过哪些坑”、“如何组合成有效工作流”的实战指南。这正是这份“Selenium-Python中文手册”想要填补的空白。它不仅仅是一份翻译文档更是一位拥有多年一线自动化测试经验的从业者的实战笔记。手册的核心目标是成为你手边的“得力助手”当你遇到元素定位失败、等待机制困惑、框架设计迷茫时能在这里找到基于真实项目经验的、可落地的解决方案。无论是刚入门的新手希望系统掌握从环境搭建到框架设计的全流程还是有一定经验的中级开发者寻求解决特定疑难杂症和性能优化的技巧这份手册都试图提供直击要害的答案。它围绕Selenium的核心能力展开结合Python的简洁语法旨在帮你构建稳定、高效、易维护的自动化测试脚本真正将自动化测试从概念转化为生产力。2. 核心能力拆解Selenium-Python的四大支柱要驾驭Selenium-Python不能只停留在“会写几行代码点按钮”的层面。我们需要深入理解其架构明白它如何与浏览器对话以及Python在其中扮演的角色。这构成了我们自动化工作的四大核心支柱。2.1 WebDriver与浏览器对话的桥梁WebDriver是Selenium的核心它遵循W3C标准是一个跨语言的协议。你可以把它想象成一个“遥控器”。你的Python代码发送指令通过这个“遥控器”WebDriver协议指挥一个具体的“机器人”浏览器驱动如chromedriver、geckodriver去操作真实的浏览器如Chrome、Firefox。关键点在于协议与实现的分离。你的Python代码调用的是selenium.webdriver库提供的统一接口如find_element,click。这些接口将指令翻译成标准的WebDriver协议通常是HTTP请求JSON数据。浏览器驱动一个独立的可执行程序监听特定端口接收这些协议命令然后通过浏览器提供的原生自动化接口如Chrome DevTools Protocol来操控浏览器。这就是为什么你需要为不同浏览器下载对应的驱动并确保驱动版本与浏览器版本大致匹配。注意驱动版本不匹配是新手最常见的错误之一常导致浏览器无法启动或行为异常。通常驱动的主版本号应与浏览器主版本号一致。建议使用如webdriver-manager这样的第三方库来自动管理驱动它能省去大量手动下载和路径配置的麻烦。2.2 元素定位自动化测试的基石一切自动化操作的前提是找到你要操作的那个网页元素。Selenium提供了多达8种定位策略但并非每种都同样常用和可靠。ID最优先选择。ID在HTML中应该是唯一的定位速度最快最稳定。driver.find_element(By.ID, “username”)Name次优选择。常用于表单元素但可能不唯一。CSS Selector最强力、最灵活的定位方式必须熟练掌握。它可以通过元素标签、类、属性、层级关系等进行精确定位。例如定位一个类为btn-primary的按钮driver.find_element(By.CSS_SELECTOR, “button.btn-primary”)。CSS Selector的语法和前端开发中的CSS选择器完全一致学习成本低功能强大。XPath功能同样强大可以遍历XML/HTML文档树。当元素没有ID、Class或者需要根据文本内容定位时XPath是救星。例如定位文本为“登录”的按钮driver.find_element(By.XPATH, “//button[text()‘登录’]”)。但XPath表达式可能较复杂且性能通常略低于CSS Selector。Link Text / Partial Link Text专门用于定位超链接a标签。Class Name定位CSS类。注意一个元素可能有多个类用空格分隔使用By.CLASS_NAME时只能匹配完整的单个类名。Tag Name按标签名定位通常用于批量查找如找出页面上所有的input标签。实操心得在真实项目中优先使用ID和CSS Selector。尽量避免使用绝对XPath以/html/body/div[1]/div[2]...开头的路径因为页面结构稍有变动就会导致定位失败。相对XPath和CSS Selector的鲁棒性要高得多。对于动态IDID包含随机字符串的元素可以尝试使用CSS Selector的部分属性匹配例如[id^‘prefix_’]匹配ID以prefix_开头的元素或[id$‘_suffix’]匹配ID以_suffix结尾的元素。2.3 浏览器操作与等待机制让脚本更“智能”找到元素后就是对它进行操作点击、输入、清空、提交等。这些操作本身很简单难点在于时机。网页是动态加载的你的代码执行速度远快于网络请求和浏览器渲染。如果元素还没出现你就去点击就会抛出NoSuchElementException。这就是等待机制至关重要的原因。Selenium主要有三种等待强制等待time.sleep(seconds)。这是最原始的方法无论元素是否就绪都死等固定时间。不推荐在正式脚本中使用因为它会不必要地拉长执行时间且无法适应网络快慢变化。隐式等待driver.implicitly_wait(seconds)。设置一个全局的等待时间。在查找任何元素时如果没立即找到WebDriver会轮询DOM直到超时。它只对find_element和find_elements方法生效。缺点是它无法等待元素的特定状态如可点击、可见。显式等待这是最佳实践。它允许你为某个特定的元素定义等待条件在指定时间内持续检查条件是否满足满足则立即返回超时则抛出异常。这需要用到WebDriverWait和expected_conditionsEC模块。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 等待一个ID为“submit”的按钮变得可点击最多等10秒 wait WebDriverWait(driver, 10) submit_button wait.until(EC.element_to_be_clickable((By.ID, “submit”))) submit_button.click()常用的EC条件包括presence_of_element_located元素出现在DOM、visibility_of_element_located元素可见、element_to_be_clickable元素可点击、text_to_be_present_in_element元素包含特定文本等。显式等待让你的脚本更健壮、更高效。2.4 框架集成从脚本到工程当你的测试用例超过几十个时一堆零散的.py文件会变得难以管理。这时就需要引入测试框架。pytest是目前Python生态中最主流的测试框架与Selenium结合得天衣无缝。为什么是pytest简洁用例写成函数用assert断言无需继承任何类。强大夹具Fixture这是pytest的杀手级功能。你可以定义pytest.fixture来管理测试资源如浏览器实例。Fixture支持作用域函数、类、模块、会话可以自动实现setup/teardown逻辑。丰富的插件生态有插件可以生成漂亮的HTML报告如pytest-html、控制用例执行顺序、分布式执行等。参数化轻松实现数据驱动测试。一个典型的Selenium pytest项目目录结构如下project/ ├── conftest.py # 存放全局fixture如浏览器初始化 ├── requirements.txt # 项目依赖 ├── test_cases/ # 测试用例目录 │ ├── __init__.py │ ├── test_login.py │ └── test_search.py ├── page_objects/ # 页面对象模型目录 │ ├── __init__.py │ ├── base_page.py │ ├── login_page.py │ └── home_page.py └── reports/ # 测试报告输出目录在conftest.py中你可以这样定义浏览器fixtureimport pytest from selenium import webdriver from selenium.webdriver.chrome.options import Options pytest.fixture(scope“function”) # 每个测试函数一个浏览器实例 def driver(): options Options() options.add_argument(“--headless”) # 无头模式不显示GUI适合CI环境 options.add_argument(“--no-sandbox”) options.add_argument(“--disable-dev-shm-usage”) driver webdriver.Chrome(optionsoptions) driver.implicitly_wait(10) # 设置全局隐式等待 yield driver # 测试函数执行时使用driver driver.quit() # 测试函数执行完毕后退出浏览器然后在测试用例中直接使用这个fixturedef test_login_success(driver): # driver fixture会自动注入 driver.get(“https://example.com/login”) # ... 执行登录操作 assert “Dashboard” in driver.title这种结构清晰、复用性高是构建可维护自动化测试项目的基石。3. 从零到一的实战搭建你的第一个自动化测试项目理论说得再多不如亲手实践。让我们抛开复杂的框架先完成一个最核心的闭环用Selenium-Python模拟用户登录一个网站并验证登录成功。这个过程会串联起环境搭建、元素定位、操作和断言。3.1 环境准备与依赖安装首先确保你有一个可用的Python环境3.6及以上。建议使用虚拟环境venv来隔离项目依赖。创建项目目录并进入mkdir my_selenium_project cd my_selenium_project创建并激活虚拟环境python -m venv venv # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate安装Selenium库pip install selenium这是最核心的库。为了省去手动管理浏览器驱动的麻烦强烈建议同时安装webdriver-managerpip install webdriver-manager可选安装pytestpip install pytest pytest-htmlpytest-html用于生成HTML测试报告。3.2 编写第一个登录测试脚本我们以一个假设的登录页面为例。假设登录页面https://example.com/login有两个输入框用户名和密码和一个提交按钮。创建一个名为test_simple_login.py的文件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 from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.chrome.service import Service # 1. 自动设置ChromeDriver路径 service Service(ChromeDriverManager().install()) # 2. 初始化浏览器驱动这里使用Chrome driver webdriver.Chrome(serviceservice) try: # 3. 打开登录页面 driver.get(“https://example.com/login”) print(f“当前页面标题: {driver.title}”) # 4. 使用显式等待确保关键元素加载完成 wait WebDriverWait(driver, 10) # 定位用户名输入框假设其ID为‘username’ username_input wait.until( EC.presence_of_element_located((By.ID, “username”)) ) # 定位密码输入框假设其ID为‘password’ password_input driver.find_element(By.ID, “password”) # 定位登录按钮假设其CSS选择器为‘button[type“submit”]’ login_button driver.find_element(By.CSS_SELECTOR, “button[type‘submit’]”) # 5. 执行操作输入用户名密码并点击登录 username_input.send_keys(“your_username”) password_input.send_keys(“your_password”) login_button.click() # 6. 验证登录是否成功 # 假设登录成功后页面标题会变化或者会出现一个独特的元素如ID为‘welcome’的欢迎信息 # 方法一验证页面标题 # wait.until(EC.title_contains(“Dashboard”)) # print(“登录成功页面标题包含‘Dashboard’。”) # 方法二验证特定元素出现更可靠 welcome_element wait.until( EC.visibility_of_element_located((By.ID, “welcome”)) ) print(f“登录成功欢迎信息: {welcome_element.text}”) except Exception as e: # 7. 异常处理与截图非常重要 print(f“测试执行过程中发生错误: {e}”) # 保存截图便于后续分析 driver.save_screenshot(“login_error.png”) raise e # 重新抛出异常让脚本失败 finally: # 8. 无论成功与否最后都要关闭浏览器 driver.quit() print(“浏览器已关闭。”)逐行解析与避坑指南自动管理驱动使用webdriver_manager它会在首次运行时自动下载匹配你Chrome浏览器版本的chromedriver并缓存起来。这彻底解决了“驱动版本不匹配”和“手动配置PATH”的难题。显式等待在输入用户名前我们等待username元素出现在DOM中。这是良好的习惯确保页面核心元素已加载。对于后续的password和button因为页面结构简单且已在同一加载周期我们直接使用find_element但实际复杂页面中对每个关键操作都使用显式等待更稳妥。定位策略示例中混合使用了ID和CSS Selector。在实际项目中你需要使用浏览器的开发者工具F12来查看元素的实际属性。优先选择唯一且稳定的属性。验证点登录成功的验证是测试的灵魂。不要只依赖页面URL或标题的变化因为它们可能不够独特。最好寻找登录后才会出现的特定元素如用户头像、欢迎标语并进行断言。这里我们使用了EC.visibility_of_element_located它要求元素不仅存在于DOM还要在页面上可见。异常处理与截图try...except...finally块是生产级脚本的标配。任何网络波动、元素变更都可能导致脚本失败。捕获异常并保存当时的屏幕截图save_screenshot是后期调试定位问题的“救命稻草”。截图文件名最好包含时间戳或用例名便于区分。资源清理driver.quit()必须放在finally块中确保即使测试失败浏览器进程也会被关闭避免资源泄露。运行这个脚本python test_simple_login.py。如果一切顺利你将看到浏览器自动打开完成登录操作并在控制台输出成功信息。恭喜你你已经完成了第一个Selenium-Python自动化操作4. 进阶实战构建页面对象模型Page Object Model, POM当测试用例越来越多你会发现相同的页面元素定位和操作代码散落在各个测试文件中。一旦页面UI发生变化你需要修改所有相关文件维护成本急剧上升。页面对象模型POM正是为了解决这个问题而生的设计模式。4.1 POM的核心思想与优势POM的核心思想是将页面的元素定位和操作封装成单独的类。测试用例只关心业务逻辑做什么而不关心具体如何操作页面怎么做。优势高复用性页面操作逻辑被封装可以在多个测试用例中重复使用。低维护成本页面元素定位符只存在于一个地方Page类。UI变更时只需修改对应的Page类。高可读性测试用例读起来像自然语言清晰表达了业务流。团队协作页面对象可以由专人维护测试人员专注于编写用例逻辑。4.2 实现一个简单的POM项目让我们重构之前的登录测试引入POM。项目结构如下my_selenium_project/ ├── pages/ │ ├── __init__.py │ └── login_page.py ├── tests/ │ └── test_login_pom.py └── conftest.py (后续用于pytest fixture)第一步创建页面对象类 (pages/login_page.py)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: 登录页面对象模型 # 1. 定位器 (Locators) - 将所有元素定位信息集中管理 USERNAME_INPUT (By.ID, “username”) PASSWORD_INPUT (By.ID, “password”) LOGIN_BUTTON (By.CSS_SELECTOR, “button[type‘submit’]”) WELCOME_MESSAGE (By.ID, “welcome”) ERROR_MESSAGE (By.CLASS_NAME, “alert-error”) # 假设的错误提示框 def __init__(self, driver): 初始化时传入driver对象 self.driver driver self.wait WebDriverWait(self.driver, 10) # 2. 页面操作 (Actions) - 封装对页面的各种操作 def open(self, url“https://example.com/login”): 打开登录页面 self.driver.get(url) return self # 支持链式调用 def enter_username(self, username): 输入用户名 username_field self.wait.until( EC.presence_of_element_located(self.USERNAME_INPUT) ) username_field.clear() username_field.send_keys(username) return self def enter_password(self, password): 输入密码 password_field self.driver.find_element(*self.PASSWORD_INPUT) password_field.clear() password_field.send_keys(password) return self def click_login(self): 点击登录按钮 login_btn self.driver.find_element(*self.LOGIN_BUTTON) login_btn.click() return self def login(self, username, password): 完整的登录流程组合操作 self.enter_username(username) self.enter_password(password) self.click_login() # 返回下一个页面的对象这里假设登录后跳转到首页 # 实际项目中这里应该返回 HomePage 对象 # from .home_page import HomePage # return HomePage(self.driver) # 3. 页面状态断言 (Assertions) - 封装对页面状态的验证 def get_welcome_message(self): 获取登录成功后的欢迎信息 welcome_element self.wait.until( EC.visibility_of_element_located(self.WELCOME_MESSAGE) ) return welcome_element.text def get_error_message(self): 获取登录失败的错误提示信息 try: error_element self.wait.until( EC.visibility_of_element_located(self.ERROR_MESSAGE) ) return error_element.text except: return None # 如果没有错误信息返回None关键设计解析定位器常量将所有By对象定义为类常量。这样修改定位方式时只需改一处。注意在find_element方法中使用时需要解包*self.USERNAME_INPUT。链式调用许多方法返回self允许你写出像page.open().enter_username(“user”).enter_password(“pass”).click_login()这样流畅的代码提升可读性。组合方法login方法将多个步骤组合在一起这是最常见的用法让测试用例更简洁。页面状态方法将断言需要的“获取文本”等操作也封装在Page类中测试用例只需调用并判断返回值。第二步编写使用POM的测试用例 (tests/test_login_pom.py)import sys import os sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ‘..’))) from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.chrome.service import Service from pages.login_page import LoginPage def test_login_success_with_pom(): # 初始化驱动 service Service(ChromeDriverManager().install()) driver webdriver.Chrome(serviceservice) try: # 初始化页面对象 login_page LoginPage(driver) # 使用页面对象执行操作 login_page.open() login_page.login(“your_username”, “your_password”) # 使用页面对象进行断言 welcome_text login_page.get_welcome_message() assert “欢迎” in welcome_text or “Welcome” in welcome_text print(f“POM模式登录成功消息: {welcome_text}”) finally: driver.quit() def test_login_failure_with_pom(): service Service(ChromeDriverManager().install()) driver webdriver.Chrome(serviceservice) try: login_page LoginPage(driver) login_page.open() login_page.login(“wrong_user”, “wrong_pass”) # 验证出现了错误提示 error_text login_page.get_error_message() assert error_text is not None assert “错误” in error_text or “Invalid” in error_text print(f“POM模式登录失败测试通过错误信息: {error_text}”) finally: driver.quit() if __name__ “__main__”: test_login_success_with_pom() test_login_failure_with_pom()可以看到测试用例变得极其清晰和简洁。业务逻辑打开页面、登录、验证结果一目了然所有关于“如何找到输入框”、“如何点击按钮”的细节都被隐藏在了LoginPage类中。这就是POM的魅力。5. 高级技巧与疑难杂症排查即使掌握了基础在实际项目中你仍会遇到各种“坑”。下面分享一些高频问题的解决思路和进阶技巧。5.1 处理弹窗、iframe与多窗口弹窗Alert/Confirm/Prompt Selenium提供了switch_to.alert来获取弹窗对象。from selenium.webdriver.common.alert import Alert # 触发一个alert后 alert Alert(driver) print(alert.text) # 获取弹窗文本 alert.accept() # 点击“确定” # alert.dismiss() # 点击“取消” # alert.send_keys(“input text”) # 用于Prompt弹窗输入iframe内嵌框架 操作iframe内的元素前必须切换到对应的iframe上下文。# 通过ID或Name切换 driver.switch_to.frame(“iframe_id_or_name”) # 通过索引切换从0开始 driver.switch_to.frame(0) # 通过WebElement切换 iframe_element driver.find_element(By.TAG_NAME, “iframe”) driver.switch_to.frame(iframe_element) # 操作iframe内的元素... # ... # 操作完成后切换回主文档 driver.switch_to.default_content() # 或者切换回上一级iframe driver.switch_to.parent_frame()多窗口/多标签页# 获取当前窗口句柄 main_window driver.current_window_handle # 点击某个链接打开新窗口 driver.find_element(By.LINK_TEXT, “Open New Window”).click() # 获取所有窗口句柄 all_windows driver.window_handles # 切换到新窗口 for window in all_windows: if window ! main_window: driver.switch_to.window(window) break # 在新窗口操作... # ... # 关闭新窗口并切回主窗口 driver.close() driver.switch_to.window(main_window)5.2 执行JavaScript与处理复杂交互有些操作通过WebDriver原生API难以实现或效率低下这时可以直接注入JavaScript。# 滚动到页面底部 driver.execute_script(“window.scrollTo(0, document.body.scrollHeight);”) # 滚动到指定元素可见 element driver.find_element(By.ID, “some-element”) driver.execute_script(“arguments[0].scrollIntoView(true);”, element) # 修改元素属性例如让一个隐藏的输入框可见 driver.execute_script(“document.getElementById(‘hidden_input’).style.display ‘block’;”) # 获取元素完整的CSS样式 styles driver.execute_script(“return window.getComputedStyle(arguments[0]);”, element) print(styles[‘color’])处理富文本编辑器如TinyMCE, CKEditor 这类编辑器通常嵌套在iframe内且其内容是一个可编辑的body。操作步骤是1) 切换到编辑器iframe2) 定位到可编辑的body元素3) 使用clear()和send_keys()输入内容或执行JS直接设置innerHTML。5.3 常见问题排查速查表问题现象可能原因排查步骤与解决方案NoSuchElementException1. 元素尚未加载完成。2. 定位表达式写错。3. 元素在iframe或shadow DOM内。4. 页面有动态ID或类名。1.增加显式等待使用EC.presence_of_element_located或EC.visibility_of_element_located。2. 使用浏览器开发者工具重新检查定位器确保语法正确、属性值无误。可先用$()或$$()在Console中测试CSS选择器。3. 检查是否需要切换iframe。4. 使用更灵活的定位策略如CSS属性部分匹配([id^‘…’])、XPath文本匹配(//button[contains(text(), ‘…’)])。ElementNotInteractableException1. 元素不可见被遮挡、display:none、visibility:hidden。2. 元素未处于可交互状态如disabled。3. 有弹窗、加载动画遮挡。1. 使用EC.element_to_be_clickable等待。2. 检查元素属性是否disabled。3.滚动元素到视口driver.execute_script(“arguments[0].scrollIntoView(true);”, element)。4. 检查是否有模态框Modal需要先关闭。脚本运行速度慢1. 过度使用time.sleep()。2. 隐式等待时间设置过长。3. 网络或应用响应慢。1.用显式等待替代强制等待。2.合理设置隐式等待时间通常5-10秒足够复杂操作可单独增加显式等待。3. 考虑在非高峰时段运行测试或优化测试环境网络。浏览器行为与人工操作不一致1. WebDriver模拟的点击/输入与真实用户事件有细微差异。2. 网站有针对自动化工具的检测。1. 尝试使用ActionChains模拟更复杂的鼠标键盘操作。2. 尝试使用driver.execute_script(“arguments[0].click();”, element)通过JS点击。3. 添加user-agent或排除自动化特征excludeSwitches: [‘enable-automation’]但需注意这可能违反某些网站的使用条款。截图是空白或不全1. 截图时机不对页面未完全渲染。2. 使用了无头模式某些渲染依赖GPU。1. 截图前增加一个短暂的显式等待确保关键元素可见。2. 对于无头模式Chrome尝试添加--disable-gpu参数新版Chrome可能已不需要。3. 使用driver.save_screenshot确保文件路径有写入权限。5.4 性能优化与最佳实践复用浏览器会话对于需要登录的测试套件可以使用pytest的scope“session”级别的fixture来初始化一次浏览器所有测试用例共用避免重复登录大幅提升执行速度。注意要做好用例间的数据隔离。并行执行使用pytest-xdist插件可以实现测试用例的并行执行充分利用多核CPU。需要确保用例之间没有依赖关系且资源如测试数据、浏览器实例管理得当。Headless模式与远程执行在CI/CD流水线中使用无头模式--headlessnew可以节省资源无需图形界面。更进一步可以使用Selenium Grid或Docker来搭建分布式测试环境实现跨浏览器、跨平台的并行测试。智能等待避免全局设置过长的隐式等待。针对不同的操作使用精确的显式等待条件。对于确实需要固定等待的场景如等待后端处理可以配合WebDriverWait和自定义的expected_condition。日志与报告集成logging模块记录详细的操作日志。结合pytest-html、Allure等生成直观的测试报告报告中应包含关键步骤截图便于失败分析。6. 与持续集成CI的融合自动化测试的价值在于持续反馈。将Selenium测试集成到CI/CD流水线如Jenkins, GitLab CI, GitHub Actions中可以实现代码提交后自动触发测试及时发现问题。一个典型的GitHub Actions工作流配置.github/workflows/python-test.yml可能如下所示name: Python Selenium Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - name: Set up Python uses: actions/setup-pythonv4 with: python-version: ‘3.9’ - name: Install system dependencies (for Chrome) run: | sudo apt-get update sudo apt-get install -y wget unzip wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - echo “deb [archamd64] http://dl.google.com/linux/chrome/deb/ stable main” | sudo tee /etc/apt/sources.list.d/google-chrome.list sudo apt-get update sudo apt-get install -y google-chrome-stable - name: Install Python dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt # 你的依赖文件包含selenium, pytest, webdriver-manager等 - name: Run tests with pytest run: | python -m pytest tests/ -v --htmlreports/report.html --self-contained-html env: # 可以在这里设置测试所需的环境变量如基础URL、账号密码等 BASE_URL: ${{ secrets.BASE_URL }} TEST_USER: ${{ secrets.TEST_USER }} TEST_PASS: ${{ secrets.TEST_PASS }} - name: Upload test report uses: actions/upload-artifactv3 if: always() # 即使测试失败也上传报告 with: name: html-report path: reports/在这个流程中每次代码推送或拉取请求都会在一个干净的Ubuntu环境中安装Chrome浏览器、安装Python依赖、运行你的pytest测试套件并生成HTML报告。你可以将报告存档或通过其他Action发送到通知渠道。关键在于将浏览器驱动管理使用webdriver-manager、无头模式运行、测试数据通过环境变量注入等环节都配置好确保测试在无界面的服务器上也能稳定执行。走到这一步你的Selenium-Python自动化测试已经从一个简单的脚本演进为一个结构清晰、易于维护、可集成到开发流程中的专业级测试解决方案。记住自动化测试不是一蹴而就的它是一个需要不断迭代、优化和适应应用变化的持续过程。从一个小用例开始逐步扩展积累页面对象完善等待策略处理各种边界情况你会慢慢构建起一道守护产品质量的可靠防线。