问题背景
在selenium驱动的web自动化中,经常会碰Chrome和chromedriver版本不匹配的状况;
本篇解决的是如何自动下载与本地Chrome版本相匹配的chromedriver。
更新日志
-
增加了对Chromium 和 MS Edge 的支持
-
支持Windows, Linux, Mac OS 平台
-
增加了对chromedriver官网来源的支持(国内还是用阿里吧)
-
修改了原方案中获取浏览器版本号的方式
-
项目地址码云
大致方案(windows)
-
获取本地Chrome版本号:从注册表HKEY_CURRENT_USERSoftwareGoogleChromeBLBeaconversion中得到;
-
获取本地chromedriver版本号:找到就返回版本号,未找到就返回 0;
-
比对版本号:Chrome Version 长这样"79.0.3945.88",取前三位版本号比对,即“79.0.3945”;
-
若不一致:去淘宝镜像下载匹配的chromedriver;
-
最终实现请直接移步到本篇末尾。
细节如下(python3实现,最后会打包成 .exe
程序,供双击运行)
-
获取Chrome版本号
import winreg # 和注册表交互 import re # 正则模块 version_re = re.compile(r'^[1-9]d*.d*.d*') # 匹配前3位版本号的正则表达式 def getChromeVersion(): try: # 从注册表中获得版本号 key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'SoftwareGoogleChromeBLBeacon') _v, type = winreg.QueryValueEx(key, 'version') print('Current Chrome Version: {}'.format(_v)) # 这步打印会在命令行窗口显示 return version_re.findall(_v)[0] # 返回前3位版本号 except WindowsError as e: print('check Chrome failed:{}'.format(e))
-
获取chromedriver版本号
-
方式(在chromedriver.exe的目录下执行cmd命令)
G:pypracchromedriver.exe --version prac 79.0.3945.36 (3582db32b33893869b8c1339e8f4d9ed1816f143-refs/branch-heads/3945@{#614})
-
代码实现如下
import subprocess # 用于执行cmd命令 def getDriverVersion(absPath): """ @param absPath: chromedriver.exe的绝对路径 """ cmd = r'{} --version'.format(absPath) # 拼接成cmd命令 try: # 执行cmd命令并接收命令回显 out, err = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() out = out.decode('utf-8') _v = out.split(' ')[1] # 拆分回显字符串,获取版本号 print('Current chromedriver Version:{}'.format(_v)) return version_re.findall(_v)[0] except IndexError as e: print('check chromedriver failed:{}'.format(e)) return 0
-
-
建个配置文件吧,用来管理chromedriver的路径(当然你也可以写在代码里,就不用本步操作了)
-
配置文件存放路径:与该程序同级
-
内容如下:
[driver] ; absolute path of chromedriver absPath=G:pypracchromedriver.exe ; DO NOT modify the url url=http://npm.taobao.org/mirrors/chromedriver/
-
定义读取上述文件的方法
from configparser import RawConfigParser # 用于解析.ini格式的配置文件 def get_ini(file): _ini = RawConfigParser() _ini.read(file, encoding='utf-8') return _ini
-
-
对比版本号
import os def checkVersionMatch(): # 读取conf.ini中的配置项 conf = get_ini('conf.ini') absPath = conf.get('driver', 'absPath') print('Chrome version compares with chromedriver version') c_v = getChromeVersion() d_v = getDriverVersion(absPath) if c_v == d_v: # 若匹配,在命令行窗口提示下面的信息 input('Chrome and chromedriver are matched. Press Enter to exit.') else: # 若不匹配,走下面的流程去下载chromedriver _v = c_v url = conf.get('driver', 'url') # 从conf.ini中获取淘宝镜像url save_d = os.path.dirname(absPath) # 下载文件的保存路径,与chromedriver同级 downLoadDriver(_v, url, save_d) # call下载文件的方法
-
下载文件并解压
import urllib.request # 发送http请求 import urllib.parse # 拼接url import zipfile # 操作.zip文件 def downLoadDriver(__v, url, save_d): # 访问淘宝镜像首页 rep = urllib.request.urlopen(url).read().decode('utf-8') # '<a href="/mirrors/chromedriver/84.0.4147.30/">84.0.4147.30/</a>' directory = re.compile(r'>(d.*?/)</a>').findall(rep) # 匹配文件夹(版本号) # 获取期望的文件夹(版本号) match_list = [] for i in directory: v = version_re.findall(i)[0] if __v == v: match_list.append(i) # http://npm.taobao.org/mirrors/chromedriver/83.0.4103.39/chromedriver_win32.zip dirUrl = urllib.parse.urljoin(url, match_list[-1]) downUrl = urllib.parse.urljoin(dirUrl, 'chromedriver_win32.zip') # 拼接出下载路径 print('will download {}'.format(downUrl)) # 指定下载的文件名和保存位置 file = os.path.join(save_d, os.path.basename(downUrl)) print('will saved in {}'.format(file)) # 开始下载,并显示下载进度(progressFunc) urllib.request.urlretrieve(downUrl, file, progressFunc) # 下载完成后解压 zFile = zipfile.ZipFile(file, 'r') for fileM in zFile.namelist(): zFile.extract(fileM, os.path.dirname(file)) zFile.close() input('Complete, press Enter to exit')
-
显示下载进度的方法
import sys def progressFunc(blocknum, blocksize, totalsize): '''作回调函数用 @blocknum: 已经下载的数据块 @blocksize: 数据块的大小 @totalsize: 远程文件的大小 ''' percent = 100.0 * blocknum * blocksize / totalsize if percent > 100: percent = 100 downsize = blocknum * blocksize if downsize >= totalsize: downsize = totalsize s = "%.2f%%" % (percent) + "====>" + "%.2f" % (downsize / 1024 / 1024) + "M/" + "%.2f" % (totalsize / 1024 / 1024) + "M " sys.stdout.write(s) sys.stdout.flush() if percent == 100: print('')
-
以线程的方式运行
import threading if __name__ == '__main__': threading.Thread(target=checkVersionMatch, args=('')).start()
打包成 .exe程序(打包教程略过,因为运行.py文件也行)
-
双击运行cdCheck.exe 即可(注意conf.ini中absPath的值)
-
.exe下载地址
-
运行效果图
-
欢迎指正交流!!!