Python Selenium POM模式下driver对象传递及属性报错解决方案
问题根因
这个报错和driver传递逻辑无关,核心是两个Python语法+POM实现逻辑的问题:
- 类实例属性定义错误:你在
LoginPage的__init__构造方法里定义emailField/passwordField/loginButton时没有加self.前缀,这三个变量只是构造方法内的局部变量,实例化后的LoginPage对象根本访问不到,直接触发AttributeError。 - 元素查找时机错误:你在构造方法里就执行DOM元素查找,实例化页面对象的瞬间就会去页面找元素,既容易因为页面未加载完成触发找不到元素的异常,后续页面刷新、跳转后这些提前缓存的元素引用还会触发陈旧元素引用(stale element reference)报错。
- 额外注意:你代码里用的
find_element_by_css_selector/find_element_by_id系列方法在Selenium 4版本已经被完全移除,运行时会抛废弃警告甚至直接报错,需要替换为find_element(By.XXX, 定位表达式)的标准写法。
修复步骤
- 调整
LoginPage类实现,不要在构造方法里直接查找元素,优先存储元素定位器,通过懒加载的方式在真正使用元素时再执行查找:
from selenium.webdriver.common.by import By from pages.basepage import BasePage class LoginPage(BasePage): # 统一维护元素定位器,后续修改定位规则只需要改这一处 _email_field_locator = (By.CSS_SELECTOR, 'input[name="username"]') _password_field_locator = (By.CSS_SELECTOR, 'input[name="password"]') _login_button_locator = (By.CSS_SELECTOR, 'input[type="submit"]') def __init__(self, driver): super().__init__(driver) self.driver = driver # 用@property装饰器实现懒加载,访问属性时才实时查找DOM元素 @property def emailField(self): return self.driver.find_element(*self._email_field_locator) @property def passwordField(self): return self.driver.find_element(*self._password_field_locator) @property def loginButton(self): return self.driver.find_element(*self._login_button_locator)
- 调整测试代码里的废弃API写法,建议补充显式等待避免页面加载时序问题:
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 pages.adminpage import AdminPage from pages.loginpage import LoginPage driver = webdriver.Chrome(ChromeDriverManager().install()) driver.get('http://localhost:8000/admin/') driver.maximize_window() loginPage = LoginPage(driver) # 等待邮箱输入框加载完成后再做焦点校验 wait = WebDriverWait(driver, 10) wait.until(EC.element_to_be_clickable(loginPage._email_field_locator)) assert driver.switch_to.active_element == loginPage.emailField # 替换废弃的find_element_by_id写法 driver.find_element(By.ID, 'djHideToolBarButton').click() loginPage.emailField.send_keys("admin@admin.com") loginPage.passwordField.send_keys("admin") loginPage.loginButton.click() adminPage = AdminPage(driver) adminPage.checkTabOrder() driver.quit()
你之前写的driver传递逻辑是完全正确的,不需要调整这部分逻辑。
内容的提问来源于stack exchange,提问作者Keiggo
相关产品推荐
相关产品推荐

