• Selenium 自动侦测浏览器版本并下载对应的浏览器驱动 | 测试开发实用技能


    本文为霍格沃兹测试学院学员 @felix 测试开发实用技能分享,供大家参考,进阶学习文末加群。

    在学院学员群交流时,有同学说 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()  
    

    实测,成功打开浏览器!

    详细代码可参考:


    来霍格沃兹测试开发学社,学习更多软件测试与测试开发的进阶技术,知识点涵盖web自动化测试 app自动化测试、接口自动化测试、测试框架、性能测试、安全测试、持续集成/持续交付/DevOps,测试左移、测试右移、精准测试、测试平台开发、测试管理等内容,课程技术涵盖bash、pytest、junit、selenium、appium、postman、requests、httprunner、jmeter、jenkins、docker、k8s、elk、sonarqube、jacoco、jvm-sandbox等相关技术,全面提升测试开发工程师的技术实力
    QQ交流群:484590337
    公众号 TestingStudio
    点击获取更多信息

  • 相关阅读:
    where field in
    看看 高考
    高分的标准
    UCOS-消息邮箱(学习笔记)
    UCOS-互斥信号量(学习笔记)
    UCOS-信号量(学习笔记)
    RVMDK的DEBUG调试-实时数据查看
    OSTimeDelay(1)
    STM32中断控制及优先级设置
    MODBUS-RTU学习
  • 原文地址:https://www.cnblogs.com/hogwarts/p/15842234.html
Copyright © 2020-2023  润新知