Selenium automated test combat | automatically detect the browser version and download the corresponding browser driver

This article is reproduced from the study notes of felix, an excellent student at Hogwarts Testing Institute, the original link: http://qrcode.testing-studio.com/f?from=51cto&url=https://ceshiren.com/tag/%E7% B2%BE%E5%8D%8E%E5%B8%96 Please indicate the source

When chatting the day before yesterday, some students said that Appium officially supports automatic downloading of compatible browser drivers. They wanted to come to Selenium to have a similar method, so they searched the Internet. Refer to the method in the previous Medium article, improve the relevant steps, and add support for multiple browsers.
First of all, think about the general steps to
identify the local browser version.
Download the driver corresponding to the browser version and
unzip it to the corresponding folder and
record it in the mapping.json file. The
next step is to roll up your sleeves and go to work to
define the directory structure
|— config
​ |— mapping.json: browser driver configuration information
|— driver: store browser drivers
|— utils
​ |— driver_util.py: packaged toolkit
|— test_search.py: test script
data ready to
import into third-party libraries, definition Constants such as good path names

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")

The first step is to get the browser version

Some minor versions of Chrome browser do not have a browser driver corresponding to the version number. You need to use the Query API to query the corresponding large version LATEST RELEASE version, and then drive the
new version of the Edge browser according to the query corresponding to the browser. Each version number of the official website has a corresponding driver download

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

code show as below

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

The second step is to download the browser driver

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")

The third step is to unzip the driver compressed package

Delete the original compressed package after decompression

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)

The fourth step, read and write configuration file information

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)

Comprehensive

Integrate the above steps into the automatic_discover_driver function, and return the browser drive path by calling this function

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

Create a test_search.py ​​file to verify whether the corresponding browser driver can be downloaded automatically

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()

Actual measurement, successfully opened the browser!

This article is reproduced from the study notes of felix, an excellent student at Hogwarts Testing Institute, the original link: http://qrcode.testing-studio.com/f?from=51cto&url=https://ceshiren.com/tag/%E7% B2%BE%E5%8D%8E%E5%B8%96 Please indicate the source

Guess you like

Origin blog.51cto.com/14293469/2561938