Selenium自动化测试实战 | 自动侦测浏览器版本并下载对应的浏览器驱动

简介: 本文转载自霍格沃兹测试学院优秀学员felix的学习笔记

本文转载自霍格沃兹测试学院优秀学员felix的学习笔记,原文链接:http://qrcode.testing-studio.com/f?from=yunqi&url=https://ceshiren.com/tag/精华帖

前天在群里聊天时,有同学说 Appium 官方支持自动下载兼容的浏览器驱动,想来Selenium也有类似的方法,于是在网上搜索一番。参考了Medium上一篇文章的方法,对相关步骤进行改进,增加了对多浏览器的支持。

首先,先想好大致上的几个步骤

  1. 识别本地浏览器版本
  2. 下载对应浏览器版本的驱动
  3. 解压到对应文件夹
  4. 记录到mapping.json文件中

接下来就是撸起袖子开干

定义好目录结构

|— config
|— mapping.json: 浏览器驱动配置信息
|— driver: 存放浏览器驱动
|— utils
|— driver_util.py: 封装的工具包
|— test_search.py: 测试脚本

数据准备

导入第三方库,定义好路径名称等常量

import json
import os
import zipfile
import shutil
import requests
import pathlib
from win32com import client as win_client


# 工作目录(当前路径调试时需加上.parent)
BASE_DIR = str(pathlib.Path.cwd())
# BASE_DIR = str(pathlib.Path.cwd().parent)

CHROME_DRIVER_BASE_URL = "https://chromedriver.storage.googleapis.com"
EDGE_DRIVER_BASE_URL = "https://msedgedriver.azureedge.net"
CHROME_DRIVER_ZIP = "chromedriver_win32.zip"
EDGE_DRIVER_ZIP = "edgedriver_win64.zip"
CHROME_DRIVER = "chromedriver.exe"
EDGE_DRIVER = "msedgedriver.exe"

BROWSER_DRIVER_DIR = str(pathlib.PurePath(BASE_DIR, "driver"))
DRIVER_MAPPING_FILE = os.path.join(BASE_DIR, "config", "mapping.json")

第一步,获取浏览器的版本

Chrome 浏览器有些小版本没有对应版本号的浏览器驱动,需要借助 Query API 查询对应大版本LATEST RELEASE版本,再根据查询对应的浏览器驱动

新版Edge 浏览器每个版本号官网都有对应的驱动下载

Latest Version API
https://chromedriver.storage.googleapis.com/LATEST_RELEASE_{version}Download Chrome Driver 
API
https://chromedriver.storage.googleapis.com/{version}/chromedriver_win32.zip
https://msedgedriver.azureedge.net/{version}/edgedriver_win64.zip

代码如下

def get_browser_version(file_path):
    """
    获取浏览器版本
    :param file_path: 浏览器文件路径
    :return: 浏览器大版本号
    """
    # 判断路径文件是否存在
    if not os.path.isfile(file_path):
        raise FileNotFoundError(f"{file_path} is not found.")
    win_obj = win_client.Dispatch('Scripting.FileSystemObject')
    version = win_obj.GetFileVersion(file_path)

    return version.strip()


def get_browser_major_version(file_path):
    """
    获取浏览器大版本号
    :param file_path: 浏览器文件路径
    :return: 浏览器大版本号
    """
    browser_ver = get_browser_version(file_path)
    browser_major_ver = browser_ver.split(".")[0]

    return browser_major_ver


def get_latest_browser_version(browser_major_ver):
    """
    获取匹配大版本的最新release版本
    :param browser_major_ver: 浏览器大版本号
    :return: 最新release版本号
    """
    latest_api = f"{CHROME_DRIVER_BASE_URL}/LATEST_RELEASE_{browser_major_ver}"
    resp = requests.get(latest_api)
    latest_driver_version = resp.text.strip()

    return latest_driver_version

第二步,下载浏览器驱动

def download_browser_driver(latest_driver_version, browser_name):
    """
    下载浏览器驱动压缩包
    :param browser_name: 浏览器名称
    :param latest_driver_version: 浏览器的版本号
    """
    download_api = None
    if browser_name == "Chrome":
        download_api = f"{CHROME_DRIVER_BASE_URL}/{latest_driver_version}/{CHROME_DRIVER_ZIP}"
    elif browser_name == "Edge":
        download_api = f"{EDGE_DRIVER_BASE_URL}/{latest_driver_version}/{EDGE_DRIVER_ZIP}"

    download_dir = os.path.join(str(BROWSER_DRIVER_DIR), os.path.basename(download_api))
    # 下载,设置超时时间20s
    resp = requests.get(download_api, stream=True, timeout=20)

    if resp.status_code == 200:
        with open(download_dir, 'wb') as fo:
            fo.write(resp.content)
    else:
        raise Exception("Download chrome driver failed") 

第三步,解驱动压缩包

解压后将原压缩包删除

def unzip_driver(browser_major_ver, browser_name):
    """
    解压驱动压缩包
    :param browser_name: 浏览器名称
    :param browser_major_ver: 浏览器大版本号
    :return: 驱动文件路径
    """
    file_path = None
    driver_path = None

    if browser_name == "Chrome":
        file_path = os.path.join(BROWSER_DRIVER_DIR, os.path.basename(CHROME_DRIVER_ZIP))
        driver_path = os.path.join(BROWSER_DRIVER_DIR, browser_major_ver, CHROME_DRIVER)
    elif browser_name == "Edge":
        file_path = os.path.join(BROWSER_DRIVER_DIR, os.path.basename(EDGE_DRIVER_ZIP))
        driver_path = os.path.join(BROWSER_DRIVER_DIR, browser_major_ver, EDGE_DRIVER)
    browser_driver_dir = os.path.join(BROWSER_DRIVER_DIR, browser_major_ver)

    # 解压到指定目录
    with zipfile.ZipFile(file_path, 'r') as zip_ref:
        zip_ref.extractall(browser_driver_dir)

    return driver_path


def remove_driver_zip(browser_name):
    """
    删除下载的驱动压缩包
    :param browser_name: 浏览器名称
    """
    file_path = None
    if browser_name == "Chrome":
        file_path = os.path.join(BROWSER_DRIVER_DIR, os.path.basename(CHROME_DRIVER_ZIP))
    elif browser_name == "Edge":
        file_path = os.path.join(BROWSER_DRIVER_DIR, os.path.basename(EDGE_DRIVER_ZIP))
    os.remove(file_path)

第四步,读写配置文件信息

def read_driver_mapping_json():
    """
    读取 mapping_json
    :return: 字典格式
    """
    if os.path.exists(DRIVER_MAPPING_FILE):
        with open(DRIVER_MAPPING_FILE) as fo:
            try:
                driver_mapping_dict = json.load(fo)
            # mapping.json内容为空时,返回空字典
            except json.decoder.JSONDecodeError:
                driver_mapping_dict = {}
    else:
        raise FileNotFoundError(f"{DRIVER_MAPPING_FILE} is not found")

    return driver_mapping_dict


def write_driver_mapping_json(browser_major_ver, latest_driver_version, driver_path, browser_name):
    """
    写入 mapping_json
    :param browser_major_ver: 浏览器大版本号
    :param latest_driver_version: 浏览器驱动版本号
    :param driver_path: 驱动存放路径
    :param browser_name: 浏览器名称
    """
    mapping_dict = read_driver_mapping_json()
    # 版本号在dict中(浏览器名不在dict中)
    if browser_major_ver in mapping_dict:

        mapping_dict[browser_major_ver][browser_name] = {
                            "driver_path": driver_path,
                            "driver_version": latest_driver_version
                }
    # 大版本号不在dict中,且字典不为空
    elif browser_major_ver not in mapping_dict and mapping_dict:
        mapping_dict[browser_major_ver] = {
            browser_name:
                {
                    "driver_path": driver_path,
                    "driver_version": latest_driver_version
                }
        }
    # 字典为空
    else:
        mapping_dict = {
            browser_major_ver:
                {
                    browser_name:
                        {
                            "driver_path": driver_path,
                            "driver_version": latest_driver_version
                        }
                }
        }
        mapping_dict.update(mapping_dict)

    with open(DRIVER_MAPPING_FILE, 'w') as fo:
        json.dump(mapping_dict, fo)

综合

将以上步骤整合到automatic_discover_driver函数中,通过调用该函数返回浏览器驱动路径

def automatic_discover_driver(browser_path, browser_name="Chrome"):
    """
    侦测浏览器驱动是否在mapping.json有记录,否则下载该驱动
    :param browser_path: 浏览器路径
    :param browser_name: 浏览器名称
    """
    browser_maj_ver = get_browser_major_version(browser_path)
    # Chrome需要获取大版本号对应的latest release version
    # Edge 可直接用当前浏览器版本号
    if browser_name == "Chrome":
        latest_browser_ver = get_latest_browser_version(browser_maj_ver)
    elif browser_name == "Edge":
        latest_browser_ver = get_browser_version(browser_path)
    else:
        raise Exception(f"{browser_name} is not found")

    # 读取mapping.json内容
    mapping_dict = read_driver_mapping_json()

    # json为空 或版本号不在mapping_dict中 或浏览器名不在mapping_dict中
    if not mapping_dict or \
            browser_maj_ver not in mapping_dict or \
            browser_name not in mapping_dict[browser_maj_ver]:

        # 下载浏览器驱动压缩包
        download_browser_driver(latest_browser_ver, browser_name)
        # 解压浏览器驱动压缩包,并返回驱动路径
        driver_path = unzip_driver(browser_maj_ver, browser_name)
        # 将浏览器大版本号、浏览器名、驱动路径、对应的浏览器版本号信息写入到mapping.json中
        write_driver_mapping_json(browser_maj_ver, latest_browser_ver, driver_path, browser_name)

        # 删除浏览器驱动压缩包
        remove_driver_zip(browser_name)

    # 返回浏览器驱动的路径
    mapping_dict = read_driver_mapping_json()
    return mapping_dict[browser_maj_ver][browser_name]["driver_path"]

测试

创建一个test_search.py文件验证是否可以自动下载对应的浏览器驱动

import pytest
from time import sleep
from selenium import webdriver
from utils.driver_util import automatic_discover_driver as automatic


class TestSearch:
    _CHROME_PATH = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
    _EDGE_PATH = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
    _browser = "Edge"

    def setup(self):
        driver_path = automatic(self._EDGE_PATH, self._browser)
        if self._browser == "Chrome":
            self.driver = webdriver.Chrome(driver_path)
        elif self._browser == "Edge":
            self.driver = webdriver.Edge(driver_path)

    def teardown(self):
        self.driver.close()
        self.driver.quit()

    def test_search_bing(self):
        self.driver.get("https://cn.bing.com/")
        self.driver.find_element_by_id("sb_form_q").send_keys("selenium")
        self.driver.find_element_by_id("sb_go_par").click()
        sleep(3)


if __name__ == '__main__':
    pytest.main()

实测,成功打开浏览器!

详细代码:https://github.com/felixzfq/StudyDemo/tree/AutomaticDiscoverBrowserDriver

更多技术文章分享及测试资料点此获取

相关文章
|
9月前
|
Web App开发 人工智能 JavaScript
主流自动化测试框架的技术解析与实战指南
本内容深入解析主流测试框架Playwright、Selenium与Cypress的核心架构与适用场景,对比其在SPA测试、CI/CD、跨浏览器兼容性等方面的表现。同时探讨Playwright在AI增强测试、录制回放、企业部署等领域的实战优势,以及Selenium在老旧系统和IE兼容性中的坚守场景。结合六大典型场景,提供技术选型决策指南,并展望AI赋能下的未来测试体系。
|
10月前
|
Web App开发 存储 前端开发
Python+Selenium自动化爬取携程动态加载游记
Python+Selenium自动化爬取携程动态加载游记
|
9月前
|
人工智能 缓存 测试技术
Playwright进阶指南 (6) | 自动化测试实战
2025企业级测试解决方案全面解析:从单元测试到千级并发,构建高可用测试体系。结合Playwright智能工具,解决传统测试维护成本高、环境依赖强、执行效率低等痛点,提升测试成功率,内容从测试架构设计、电商系统实战框架、高级测试策略、Docker化部署、CI/CD集成及AI测试应用,助力测试工程师掌握前沿技术,打造高效稳定的测试流程。
Playwright进阶指南 (6) | 自动化测试实战
|
8月前
|
人工智能 数据可视化 测试技术
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
990 11
|
Web App开发 前端开发 JavaScript
探索Python科学计算的边界:利用Selenium进行Web应用性能测试与优化
【10月更文挑战第6天】随着互联网技术的发展,Web应用程序已经成为人们日常生活和工作中不可或缺的一部分。这些应用不仅需要提供丰富的功能,还必须具备良好的性能表现以保证用户体验。性能测试是确保Web应用能够快速响应用户请求并处理大量并发访问的关键步骤之一。本文将探讨如何使用Python结合Selenium来进行Web应用的性能测试,并通过实际代码示例展示如何识别瓶颈及优化应用。
883 5
|
10月前
|
人工智能 JavaScript 前端开发
Playwright自动化测试系列课(5) | ​​调试神器实战:Trace Viewer 录屏分析 + AI 辅助定位修复​
Playwright 的 Trace Viewer 提供录屏级追踪,还原测试全过程,帮助定位偶发故障。结合 AI 实现自动修复,大幅提升调试效率,成为自动化测试利器。
|
Web App开发 数据采集 JavaScript
CDP与Selenium相结合——玩转网页端自动化数据采集/爬取程序
本文介绍了Selenium、Chrome DevTools及Chrome DevTools Protocol (CDP) 的基本功能与应用。Selenium是一款开源自动化测试工具,适用于网页端应用程序测试和数据采集,具备跨平台特性。Chrome DevTools内置浏览器中,提供调试、分析Web应用程序的功能,包括元素、控制台、源代码和网络选项卡等。CDP是一套用于与Chromium内核浏览器通信的API,支持自动化测试和性能分析。文中还展示了Selenium与CDP结合使用的示例,如捕获网络请求数据和打印网页内容,并推荐了相关书籍和资源以供深入学习。
2079 39
CDP与Selenium相结合——玩转网页端自动化数据采集/爬取程序
|
Web App开发 IDE JavaScript
Selenium IDE:Web自动化测试的得力助手
Selenium IDE:Web自动化测试的利器。作为开源工具,Selenium IDE支持录制与回放用户操作,适用于Chrome、Firefox等多浏览器,简化了测试流程,提升了效率,降低了自动化测试的门槛。它还支持导出多种编程语言的脚本,便于测试集成与复用。
488 31
Selenium IDE:Web自动化测试的得力助手
|
机器学习/深度学习 设计模式 测试技术
Python 高级编程与实战:构建自动化测试框架
本文深入探讨了Python中的自动化测试框架,包括unittest、pytest和nose2,并通过实战项目帮助读者掌握这些技术。文中详细介绍了各框架的基本用法和示例代码,助力开发者快速验证代码正确性,减少手动测试工作量。学习资源推荐包括Python官方文档及Real Python等网站。
|
人工智能 测试技术 API
Windows用户必备:Postman v11详细安装指南与API测试入门教程(附官网下载
Postman是全球领先的API开发与测试工具,支持REST、SOAP、GraphQL等协议调试。2025年最新版v11新增AI智能生成测试用例、多环境变量同步等功能,适用于前后端分离开发、自动化测试、接口文档自动生成及团队协作共享API资源。本文详细介绍Postman的软件定位、核心功能、安装步骤、首次配置、基础使用及常见问题解答,帮助用户快速上手并高效利用该工具进行API开发与测试。