自动侦测浏览器版本并下载对应的浏览器驱动

发表于:2020-5-19 11:17

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:北漠丶    来源:博客园

  昨天在群里聊天时,有同学说 Appium 官方支持自动下载兼容的浏览器驱动,想来Selenium也有类似的方法,于是在网上搜索一番。参考了Medium上一篇文章的方法,对步骤进行改进,增加了对多浏览器的支持。
  首先,先想好大致上的几个步骤
  识别本地浏览器版本
  下载对应浏览器版本的驱动
  解压到对应文件夹
  记录到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/AutomaticDiscoverBrowserDriver

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号