Python+Selenium自动化测试入门:从环境搭建到Page Object模式实战

📅 2026/8/13 23:42:08
Python+Selenium自动化测试入门:从环境搭建到Page Object模式实战
1. 从“手动点点点”到“脚本自己跑”为什么我们需要自动化测试如果你是一名测试工程师或者是一名需要对自己代码负责的开发那么“自动化测试”这个词你一定不陌生。但很多时候它就像一个挂在嘴边的“高级”概念听起来很美做起来却无从下手。我见过太多团队测试工作还停留在“人肉点点点”的阶段每次发版前测试同学加班加点重复着枯燥的点击、输入、验证效率低下不说还容易因为疲劳而出错。更头疼的是一旦功能迭代这些手动测试用例又得重新来一遍人力成本和时间成本都高得吓人。自动化测试的核心价值就是把这些重复、机械、有明确规则的测试动作用代码脚本的形式固化下来让机器去执行。它的目标从来不是取代测试工程师而是把测试工程师从重复劳动中解放出来让他们有更多时间去思考更复杂的测试场景、去设计更有价值的测试用例、去探索那些自动化难以覆盖的边界。想象一下当你提交代码后一套完整的自动化测试脚本在后台自动运行几分钟内就告诉你核心功能是否正常这不仅能快速反馈更能极大地提升团队的交付信心和效率。从网络上的热词也能看出大家的关注点selenium自动化测试、appium自动化测试、python自动化测试、接口自动化测试这些都是不同层面的自动化实践。而像shell脚本、windows脚本命令闪退、npm : 无法将“npm”项识别为 cmdlet...这类问题则暴露了大家在迈出第一步时遇到的各种环境与执行层面的“拦路虎”。今天我就以一个过来人的身份抛开那些华而不实的理论框架手把手带你从零开始写出一份真正能跑起来、有实用价值的自动化测试脚本。我们会聚焦在最通用、也最容易上手的Python Selenium进行Web UI自动化但其中蕴含的脚本编写思想、问题排查方法适用于任何类型的自动化测试。2. 工欲善其事环境搭建与第一个“Hello World”脚本在开始编写复杂的业务流测试之前我们必须先把地基打牢。很多新手卡在第一步不是因为逻辑多难而是环境没配好脚本根本跑不起来。我们一步步来避开那些常见的坑。2.1 核心工具选型为什么是Python Selenium对于UI自动化测试Selenium是事实上的行业标准。它支持多种浏览器Chrome, Firefox, Edge等和多种编程语言Java, Python, C#, JavaScript等。我选择Python作为脚本语言原因有三首先语法简洁上手极快测试脚本的可读性高其次生态丰富pip安装各种库如用于数据驱动的pytest、用于报告生成的Allure非常方便最后Python在测试领域应用广泛社区活跃遇到问题容易找到解决方案。所以我们的技术栈很明确Python 3.xSelenium浏览器驱动。接下来就是具体的安装步骤。2.2 详细环境配置步骤与避坑指南第一步安装Python去Python官网下载最新稳定版的安装包。安装时务必勾选“Add Python to PATH”这个选项。这是无数新手踩坑的起点。如果不勾选你会在命令行里遇到python : 无法将“python”项识别为 cmdlet...这类错误这和热词里npm、opencode报错是同一性质的问题——系统找不到这个命令。安装完成后打开命令行CMD或PowerShell输入python --version或python -V。如果能看到版本号如Python 3.11.4恭喜你第一步成功了。如果报错你需要手动将Python的安装目录如C:\Users\你的用户名\AppData\Local\Programs\Python\Python311和其下的Scripts目录添加到系统的环境变量PATH中。第二步安装Selenium库Python自带包管理工具pip。在命令行中输入pip install selenium如果下载速度慢可以使用国内镜像源例如pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple安装成功后可以进入Python交互模式 (python)输入import selenium不报错即表示安装成功。第三步下载浏览器驱动以Chrome为例这是最关键也最容易出错的一步。Selenium本身只是一个控制浏览器的“遥控器”它需要对应的“驱动程序”才能实际操控浏览器。这个驱动必须和你的浏览器版本严格匹配。查看你的Chrome浏览器版本打开Chrome点击右上角三个点 - 帮助 - 关于Google Chrome。打开 ChromeDriver 官网 或国内镜像站。下载与你的Chrome版本号完全一致的驱动文件例如Chrome版本是115.0.5790.102就找主版本号为115的ChromeDriver。下载的是一个可执行文件如chromedriver.exe。处理这个文件有三种常用方法我推荐第三种方法一不推荐将其放在Python的安装目录下。容易混乱。方法二不推荐将其放在你的项目目录下。每个项目都要放一份麻烦。方法三推荐将其放在一个固定目录如C:\WebDriver\bin然后将此目录路径添加到系统的环境变量PATH中。这是一劳永逸的做法任何项目、在任何路径下都能直接调用。重要提示很多同学遇到WebDriverException: Message: ‘chromedriver’ executable needs to be in PATH错误根本原因就是系统找不到chromedriver.exe。请严格按照上述步骤检查路径。另外如果浏览器自动更新了版本记得也要更新对应的驱动否则同样会报错。2.3 第一个脚本让浏览器自动打开百度环境配好了我们来写一个最简单的脚本验证一下。创建一个新文件命名为first_test.py。# first_test.py from selenium import webdriver from selenium.webdriver.common.by import By import time # 1. 创建浏览器驱动对象 # 这会启动一个全新的、干净的Chrome浏览器窗口 driver webdriver.Chrome() try: # 2. 打开目标网址 driver.get(https://www.baidu.com) # 等待2秒让我们能看到页面加载完成 time.sleep(2) # 3. 找到搜索输入框并输入关键词“自动化测试” # 通过元素的ID属性来定位这是最准确快速的方式之一 search_box driver.find_element(By.ID, kw) search_box.send_keys(自动化测试) # 4. 找到“百度一下”按钮并点击 search_button driver.find_element(By.ID, su) search_button.click() # 5. 等待3秒查看搜索结果 time.sleep(3) # 可选打印当前页面的标题 print(当前页面标题是, driver.title) finally: # 6. 关闭浏览器 # 使用try-finally确保即使中间出错浏览器也会被关闭避免残留进程 driver.quit()保存文件在命令行中切换到该文件所在目录运行python first_test.py如果一切顺利你将看到Chrome浏览器自动打开访问百度输入“自动化测试”点击搜索然后展示结果页最后关闭。恭喜你你的第一个自动化测试脚本成功了这个过程模拟了一个最核心的用户操作定位元素 - 操作元素输入/点击。3. 脚本的核心骨架元素定位、操作与等待第一个脚本虽然跑通了但非常脆弱。网络慢一点、页面元素加载晚一点脚本就会因为找不到元素而报错崩溃。一个健壮的自动化脚本必须处理好这三个核心问题如何精准地找到元素找到后如何操作如何优雅地等待元素出现3.1 八种元素定位方法详解与选用策略driver.find_element(By.XXX, “value”)是找到页面上某个元素的钥匙。Selenium提供了8种主要的定位方式我按推荐优先级排序ID (By.ID): 优先级最高。ID在HTML中应该是唯一的定位最快、最准确。就像人的身份证号。上例中的kw和su就是百度搜索框和按钮的ID。Name (By.NAME): 次选。Name属性也常用于表单元素但可能不唯一。CSS Selector (By.CSS_SELECTOR):我最常用、也最推荐掌握的高级定位方式。它功能强大语法灵活可以通过id、class、属性、层级关系等进行组合定位。例如#kw定位ID为kw的元素等价于By.ID。.s_ipt定位class包含s_ipt的元素。input[name‘wd’]定位name属性为wd的input元素。#form span input通过层级关系定位。XPath (By.XPATH): 功能同样强大可以遍历XML/HTML文档。但写起来复杂性能通常略低于CSS Selector。在CSS无法定位的复杂场景下使用例如//input[id‘kw’]定位id为kw的input元素。//span[contains(text(), ‘新闻’)]定位文本包含“新闻”的span元素。Class Name (By.CLASS_NAME): 定位class属性。注意一个元素可能有多个class如class“btn btn-primary”此时需要用CSS Selector。Tag Name (By.TAG_NAME): 按标签名定位如input,div,a。通常一个页面有很多同类标签不唯一需结合其他方法。Link Text (By.LINK_TEXT): 精确匹配超链接的完整文本。Partial Link Text (By.PARTIAL_LINK_TEXT): 匹配超链接的部分文本。实操心得在浏览器的开发者工具F12中使用CtrlF可以在Elements面板打开搜索框直接输入CSS Selector或XPath进行实时高亮匹配这是调试定位表达式最快的方法。优先使用ID和CSS Selector尽量避免使用过于复杂脆弱的XPath特别是包含大量索引如div[3]/div[5]/span[2]的绝对路径页面结构一变就失效。3.2 元素操作不仅仅是点击和输入找到元素后我们可以对它进行一系列操作模拟用户行为点击element.click()输入文本element.send_keys(“your_text”)清空输入框element.clear()获取文本element.text用于断言验证获取属性element.get_attribute(“href”)如获取链接地址判断是否显示/可用element.is_displayed(),element.is_enabled()一个常见的组合操作是先清空再输入。search_box driver.find_element(By.ID, “kw”) search_box.clear() # 防止输入框有默认内容 search_box.send_keys(“新的关键词”)3.3 三种等待机制让脚本“聪明”地等待time.sleep(3)这种固定等待是“笨”办法它无条件等待固定时间无论页面是否加载完成。这会造成时间浪费如果页面1秒就加载好了或等待不足如果网络差3秒还没加载好。我们必须使用更智能的等待。隐式等待 (Implicit Wait)设置一个全局的超时时间。在设置时间内WebDriver会轮询DOM去寻找元素如果找到则立即继续如果超时还没找到则抛出NoSuchElementException。driver.implicitly_wait(10) # 单位秒注意隐式等待只需要设置一次对整个driver生命周期都有效。但它只对find_element这类查找操作有效。显式等待 (Explicit Wait)这是处理动态加载元素的最佳实践。它针对某个特定的元素和条件进行等待更加灵活精准。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 等待最多10秒直到ID为‘kw’的元素可见 wait WebDriverWait(driver, 10) search_box wait.until(EC.visibility_of_element_located((By.ID, “kw”))) search_box.send_keys(“自动化测试”)expected_conditions模块提供了很多等待条件如element_to_be_clickable元素可点击、presence_of_element_located元素存在于DOM等。显式等待是编写稳定脚本的关键。强制等待 (Sleep)time.sleep()。除非极特殊情况如等待一个非Web的弹窗、固定动画否则应尽量避免使用。我的经验是在脚本开头设置一个较短的隐式等待如5秒作为兜底。在关键操作步骤尤其是点击后页面跳转、异步加载数据时使用显式等待来等待特定元素出现。这能最大程度保证脚本的稳定性和执行效率。4. 构建可维护的测试脚本Page Object模式实战当测试用例越来越多如果你把所有定位和操作都堆在一个脚本文件里很快就会变成难以维护的“意大利面条式”代码。查找元素的选择器散落在各处页面UI一变你需要修改无数个测试文件。这时我们需要引入Page Object设计模式。4.1 Page Object模式是什么为什么需要它Page Object模式的核心思想是将一个Web页面抽象成一个Python类页面上的元素就是这个类的属性页面上的操作如登录、搜索就是这个类的方法。而测试用例脚本只关心业务逻辑和测试数据不关心页面元素如何定位。这样做的好处非常明显代码复用相同的页面元素定位和操作逻辑只写一次。易于维护当页面UI改变时你只需要修改对应的Page Object类所有用到该页面的测试用例都自动生效。可读性强测试用例读起来就像自然语言例如home_page.search(“关键词”)。4.2 实战将百度搜索重构为Page Object我们以百度首页和搜索结果页为例进行重构。第一步创建页面对象类新建一个目录pages在里面创建两个Python文件。pages/baidu_home_page.py:# baidu_home_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 BaiduHomePage: # 页面元素定位器 (Locators) SEARCH_INPUT (By.ID, “kw”) # 搜索框 SEARCH_BUTTON (By.ID, “su”) # “百度一下”按钮 def __init__(self, driver): # 初始化方法接收一个driver对象 self.driver driver self.wait WebDriverWait(driver, 10) def load(self): # 打开页面 self.driver.get(“https://www.baidu.com”) return self def search(self, keyword): # 搜索操作输入关键词并点击搜索 # 使用显式等待确保元素可交互 search_input self.wait.until(EC.element_to_be_clickable(self.SEARCH_INPUT)) search_input.clear() search_input.send_keys(keyword) search_button self.wait.until(EC.element_to_be_clickable(self.SEARCH_BUTTON)) search_button.click() # 返回搜索结果页的对象实现链式调用 from pages.baidu_result_page import BaiduResultPage return BaiduResultPage(self.driver)pages/baidu_result_page.py:# baidu_result_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 BaiduResultPage: # 结果页的元素例如第一个结果的标题 FIRST_RESULT_TITLE (By.CSS_SELECTOR, “#content_left .result h3 a”) def __init__(self, driver): self.driver driver self.wait WebDriverWait(driver, 10) def get_first_result_title(self): # 获取第一个搜索结果的标题文本 first_result self.wait.until(EC.presence_of_element_located(self.FIRST_RESULT_TITLE)) return first_result.text第二步编写清爽的测试用例新建测试脚本test_baidu_search.py。# test_baidu_search.py import pytest from selenium import webdriver from pages.baidu_home_page import BaiduHomePage class TestBaiduSearch: def setup_method(self): # 每个测试方法开始前执行启动浏览器 self.driver webdriver.Chrome() self.driver.implicitly_wait(5) # 设置隐式等待 def teardown_method(self): # 每个测试方法结束后执行关闭浏览器 self.driver.quit() def test_search_keyword(self): # 测试用例搜索特定关键词并验证结果 home_page BaiduHomePage(self.driver) # 链式调用打开首页 - 搜索 - 进入结果页 result_page home_page.load().search(“自动化测试”) # 获取结果并断言 first_title result_page.get_first_result_title() assert “自动化” in first_title.lower() # 断言标题中包含“自动化” print(f“第一个搜索结果标题是{first_title}”) def test_search_another_keyword(self): # 另一个测试用例结构清晰 home_page BaiduHomePage(self.driver) result_page home_page.load().search(“Selenium”) first_title result_page.get_first_result_title() assert “selenium” in first_title.lower() print(f“第一个搜索结果标题是{first_title}”) if __name__ “__main__”: # 可以直接运行这个脚本 import sys pytest.main([sys.argv[0], “-v”])运行这个测试脚本你会发现业务逻辑变得异常清晰。测试用例test_search_keyword里看不到任何find_element或By.ID只有load()、search()、get_first_result_title()这些语义明确的方法。这就是Page Object模式的魅力。当百度搜索框的ID某天从kw改成searchInput时你只需要修改baidu_home_page.py文件中的一行代码所有测试用例就都修复了。5. 让脚本更强大数据驱动、测试报告与常见问题排查一个完整的自动化测试项目不仅仅是能跑通的脚本。我们还需要考虑如何管理大量的测试数据如何生成直观的测试报告以及如何应对执行过程中的各种“意外”。5.1 数据驱动测试用数据文件管理用例硬编码测试数据在脚本里如search(“自动化测试”)是不可维护的。数据驱动测试DDT将测试数据和测试逻辑分离。我们可以使用pytest框架的pytest.mark.parametrize装饰器轻松实现。首先安装pytestpip install pytest。然后我们改造之前的测试用例# test_baidu_search_ddt.py import pytest from selenium import webdriver from pages.baidu_home_page import BaiduHomePage # 将测试数据定义在装饰器里 pytest.mark.parametrize(“keyword, expected_text”, [ (“自动化测试”, “自动化”), (“Python”, “python”), (“Selenium”, “selenium”), (“接口测试”, “接口”), ]) def test_search_with_different_keywords(keyword, expected_text): driver webdriver.Chrome() driver.implicitly_wait(5) try: home_page BaiduHomePage(driver) result_page home_page.load().search(keyword) first_title result_page.get_first_result_title() # 断言结果标题中包含期望的关键词 assert expected_text in first_title.lower() print(f“搜索 ‘{keyword}’ 第一个结果标题: {first_title}”) finally: driver.quit()运行pytest test_baidu_search_ddt.py -v你会看到4条测试用例被依次执行。测试数据和用例逻辑完全分离新增一个测试场景只需要在参数列表里加一行数据即可。对于更复杂的数据你可以从JSON、YAML、Excel或数据库中读取。5.2 生成专业测试报告使用Allure命令行输出的结果不够直观。Allure是一个能生成非常美观、交互式测试报告的工具。结合pytest使用效果极佳。安装Allure命令行工具和pytest插件。pip install allure-pytest还需要单独安装Allure命令行工具请参考其官方文档在测试脚本或conftest.py中配置钩子用于截图这在测试失败时非常有用。# conftest.py import pytest from selenium import webdriver import allure import os pytest.hookimpl(tryfirstTrue, hookwrapperTrue) def pytest_runtest_makereport(item, call): outcome yield rep outcome.get_result() if rep.when “call” and rep.failed: # 如果测试用例执行失败 if “driver” in item.funcargs: driver item.funcargs[“driver”] # 截图并附加到Allure报告 take_screenshot(driver, item.name) def take_screenshot(driver, name): screenshot_dir “./screenshots” os.makedirs(screenshot_dir, exist_okTrue) file_path f“{screenshot_dir}/{name}.png” driver.save_screenshot(file_path) allure.attach.file(file_path, name“失败截图”, attachment_typeallure.attachment_type.PNG)运行测试并生成报告。# 运行测试生成Allure结果数据 pytest test_baidu_search_ddt.py -v --alluredir./allure-results # 启动本地服务查看报告 allure serve ./allure-results报告会展示用例通过率、执行时长、失败用例的截图和日志便于团队分析和追溯。5.3 高频问题排查手册避坑指南结合热词和我的经验以下是新手最常遇到的几个问题及解决方案问题一WebDriverException: Message: ‘chromedriver’ executable needs to be in PATH原因系统找不到ChromeDriver。解决确认ChromeDriver已下载且版本与浏览器匹配。将chromedriver.exe所在目录添加到系统环境变量PATH中或直接在代码中指定路径driver webdriver.Chrome(executable_path‘C:/path/to/chromedriver.exe’)注意新版本Selenium推荐使用Service类。问题二NoSuchElementException原因脚本执行太快页面元素还没加载出来或定位表达式写错了。解决使用显式等待代替time.sleep和隐式等待。检查定位表达式在浏览器开发者工具中使用CtrlF验证你的CSS Selector或XPath是否能唯一匹配到目标元素。注意iframe如果元素在iframe里需要先driver.switch_to.frame(frame_element)切换到该iframe内才能定位。问题三ElementNotInteractableException原因元素存在但不可交互如被遮挡、未显示、是disabled状态。解决使用EC.element_to_be_clickable进行等待。检查是否有弹窗、蒙层遮挡了目标元素。尝试用JavaScript直接操作driver.execute_script(“arguments[0].click();”, element)问题四脚本在无界面环境如Jenkins服务器运行失败原因服务器没有图形界面无法启动普通Chrome。解决使用无头模式Headless Mode。from selenium.webdriver.chrome.options import Options chrome_options Options() chrome_options.add_argument(“--headless”) # 启用无头模式 chrome_options.add_argument(“--disable-gpu”) # 禁用GPU某些环境需要 chrome_options.add_argument(“--no-sandbox”) # Linux环境可能需要 driver webdriver.Chrome(optionschrome_options)问题五如何处理浏览器弹窗Alert/Confirm/Prompt解决使用driver.switch_to.alert。alert driver.switch_to.alert print(alert.text) # 获取弹窗文本 alert.accept() # 点击“确定” # alert.dismiss() # 点击“取消” # alert.send_keys(“input text”) # 用于Prompt弹窗输入编写自动化测试脚本是一个从“会动”到“稳定”再到“优雅”的过程。它不仅仅是技术活更是对测试思维和工程化能力的锻炼。从环境搭建到第一个脚本从元素定位到等待策略再到用Page Object模式组织代码最后用数据驱动和报告来完善整个流程每一步都踩过坑也都有成熟的解决方案。记住最好的学习方式就是动手。找一个你熟悉的网站从登录、搜索这样的小功能开始模仿本文的步骤写出你的第一个自动化脚本。遇到报错不要慌仔细阅读错误信息善用搜索引擎和开发者工具你遇到的问题99%都已经有人解决过了。当你成功地将一个重复的手工测试任务自动化看着脚本稳稳地执行那份成就感和效率的提升就是坚持下去的最大动力。