問題背景
在selenium驅動的web自動化中,經常會碰Chrome和chromedriver版本不匹配的狀況;
本篇解決的是如何自動下載與本地Chrome版本相匹配的chromedriver。
更新日志
-
增加了對Chromium 和 MS Edge 的支持
-
支持Windows, Linux, Mac OS 平台
-
增加了對chromedriver官網來源的支持(國內還是用阿里吧)
-
修改了原方案中獲取瀏覽器版本號的方式
-
項目地址碼雲
大致方案(windows)
-
獲取本地Chrome版本號:從注冊表HKEY_CURRENT_USER\Software\Google\Chrome\BLBeacon\version中得到;
-
獲取本地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'Software\Google\Chrome\BLBeacon') _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:\py\prac\chromedriver.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:\py\prac\chromedriver.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 \r" 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下載地址
-
運行效果圖
-
歡迎指正交流!!!