Selenium 3/4 跨版本兼容方案
目录
一、版本兼容方案设计
功能点 | Selenium 3 实现方式 | Selenium 4 实现方式 | 兼容处理方案 |
---|---|---|---|
浏览器初始化 | webdriver.Chrome("chromedriver.exe") | webdriver.Chrome(service=Service()) | 版本检测自动选择 |
元素定位 | find_element_by_* 系列方法 | find_element(By.*) | 封装统一查找方法 |
等待机制 | 直接使用WebDriverWait | 新增expected_conditions 别名 | 保持相同调用方式 |
以下是针对 Selenium 3/4 跨版本兼容方案的优化建议和补充实现,重点解决元素定位兼容性、异常处理和代码健壮性问题:
二、优化元素定位方法
def _get_by_type(self, locator):
"""统一处理Selenium 3/4的定位器类型映射"""
locator = locator.lower().replace(' ', '_')
mapping = {
'id': By.ID,
'xpath': By.XPATH,
'css': By.CSS_SELECTOR,
'css_selector': By.CSS_SELECTOR,
'name': By.NAME,
'class_name': By.CLASS_NAME,
'class': By.CLASS_NAME,
'link_text': By.LINK_TEXT,
'link': By.LINK_TEXT,
'partial_link_text': By.PARTIAL_LINK_TEXT,
'partial_link': By.PARTIAL_LINK_TEXT,
'tag_name': By.TAG_NAME,
'tag': By.TAG_NAME
}
return mapping.get(locator)
三、增强的元素查找方法
def find_elements(self, locator, value, timeout=None):
"""查找多个元素的兼容实现"""
by_type = self._get_by_type(locator)
if not by_type:
raise ValueError(f"Invalid locator type: {locator}")
if timeout:
try:
return self.wait.until(
EC.presence_of_all_elements_located((by_type, value))
)
except TimeoutException:
return []
if SELENIUM4:
return self.driver.find_elements(by_type, value)
else:
method = f"find_elements_by_{locator}"
if hasattr(self.driver, method):
return getattr(self.driver, method)(value)
return self.driver.find_elements(by_type, value)
四、浏览器选项兼容处理
def _create_default_options(self):
"""创建跨版本的浏览器选项"""
browser_cls = getattr(webdriver, f"{self.browser.capitalize()}Options", None)
if not browser_cls:
raise ValueError(f"Unsupported browser: {self.browser}")
options = browser_cls()
common_args = [
'--disable-infobars',
'--disable-extensions',
'--disable-gpu',
'--no-sandbox',
'--disable-dev-shm-usage'
]
for arg in common_args:
options.add_argument(arg)
# 特殊版本处理
if self.browser == 'chrome' and not SELENIUM4:
options.add_argument('--disable-blink-features=AutomationControlled')
return options
五、异常处理增强
def safe_click(self, locator, value, timeout=10):
"""带异常处理的点击操作"""
try:
element = self.wait_element(locator, value, timeout)
element.click()
return True
except (TimeoutException, NoSuchElementException) as e:
print(f"Click failed: {str(e)}")
return False
except WebDriverException as e:
print(f"WebDriver error: {str(e)}")
raise
六、等待机制优化
def wait_element(self, locator, value, timeout=None):
"""增强的等待机制"""
by_type = self._get_by_type(locator)
wait = WebDriverWait(self.driver, timeout or 10)
return wait.until(
EC.presence_of_element_located((by_type, value)),
message=f"Element not found: {locator}={value}"
)
七、驱动自动发现逻辑
def _get_driver_path(self, driver_path, browser):
"""自动发现驱动路径"""
if driver_path and os.path.exists(driver_path):
return driver_path
# 尝试从环境变量获取
env_var = f"{browser.upper()}_DRIVER_PATH"
if env_var in os.environ:
return os.environ[env_var]
# 常见安装路径检查
common_paths = {
'chrome': [
'/usr/local/bin/chromedriver',
'/usr/bin/chromedriver',
'C:/WebDriver/bin/chromedriver.exe'
],
'firefox': [
'/usr/local/bin/geckodriver',
'/usr/bin/geckodriver',
'C:/WebDriver/bin/geckodriver.exe'
]
}
for path in common_paths.get(browser, []):
if os.path.exists(path):
return path
raise FileNotFoundError(
f"Driver not found for {browser}. Please specify path manually."
)
八、新增功能方法
def execute_js(self, script, *args):
"""执行JavaScript的兼容方法"""
if SELENIUM4:
return self.driver.execute_script(script, *args)
else:
# Selenium 3的特殊处理
if len(args) == 1 and isinstance(args[0], (list, tuple)):
return self.driver.execute_script(script, *args[0])
return self.driver.execute_script(script, args)
九、窗口管理兼容
def switch_to_window(self, handle_or_index):
"""窗口切换的兼容实现"""
if isinstance(handle_or_index, int):
handles = self.driver.window_handles
if 0 <= handle_or_index < len(handles):
return self.driver.switch_to.window(handles[handle_or_index])
raise IndexError("Window index out of range")
return self.driver.switch_to.window(handle_or_index)
这些优化方案保持了核心兼容逻辑,同时:
- 增强了错误处理和日志记录
- 改进了元素定位的灵活性
- 添加了常用操作的便捷方法
- 完善了自动发现机制
- 保持了代码的清晰结构和可维护性