解决Chrome与ChromeDriver版本不一致问题的Python方案


需求背景

由于Chrome是自动更新的,在浏览器里面也没办法关闭这一选项,而自动升级总是很容易带来问题.例如ChromeDriver不兼容的问题

selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 83

在使用PythonSelenium模块的时候,就会因为这个问题报错而导致任务不会如期运行

所以我琢磨着写一个自动更新ChromeDriver的程序,伪代码是这样的

try:
	selenium程序()
except:
	自动更新ChromeDriver程序()

干活

主体架构如下:

- 获取Chrome版本()
- 获取ChromeDriver版本列表()
- 核对版本信息,获取最接近的ChromeDriver版本号()
- 拼接下载链接,下载文件()
- 解压文件()
- 替换文件()

获取Chrome版本

这一方法需要通过注册表来获取

def getChromeVersion():
	import winreg
	key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,r'Software\Google\Chrome\BLBeacon')
	chrome_version = winreg.QueryValueEx(key,'version')[0]
	return chrome_version

chrome = getChromeVersion()

我电脑中运行的结果,获取到的版本是这样的

>>> chrome
'80.0.3987.162'

获取ChromeDriver版本

这里需要抓取网页源码,利用正则从网页源码提取版本信息用以核对

URL = 'http://chromedriver.storage.googleapis.com/?delimiter=/&prefix='
REG = r'<Prefix>(\d.*?)</Prefix>'

def getChromeDriverVersion(link,regexp):
        # 从网页源代码获取目前提供的版本号
        # 返回列表
        from re import findall
        from requests import get
        resp = get(link)
        driver_version = findall(regexp,resp.text) # 返回正则括号中结果的列表
        return driver_version

driver = getChromeDriverVersion(URL,REG)

这一段需要注意,ChromeDriver的原本地址是不会告诉你上面的地址的.地址见这篇

ChromeDriver下载地址

get到的网页源代码都是js,是看不到任何版本信息的.但是仔细观察可以发现是有一段链接是有完整版本号的.就是上面这段url

至于正则,这是一段很简单的正则,因为网页源代码的结构很简单,就直接取数字和小数点了
在这里插入图片描述

这一段我的运行结果如下

>>> driver
['2.0/','2.1/','2.10/','2.11/','2.12/','2.13/','2.14/','2.15/','2.16/','2.17/','2.18/','2.19/','2.2/','2.20/','2.21/','2.22/','2.23/','2.24/','2.25/','2.26/','2.27/','2.28/','2.29/','2.3/','2.30/','2.31/','2.32/','2.33/','2.34/','2.35/','2.36/','2.37/','2.38/','2.39/','2.4/','2.40/','2.41/','2.42/','2.43/','2.44/','2.45/','2.46/','2.5/','2.6/','2.7/','2.8/','2.9/',
'70.0.3538.16/','70.0.3538.67/','70.0.3538.97/','71.0.3578.137/','71.0.3578.30/','71.0.3578.33/','71.0.3578.80/','72.0.3626.69/','72.0.3626.7/','73.0.3683.20/','73.0.3683.68/','74.0.3729.6/','75.0.3770.140/','75.0.3770.8/','75.0.3770.90/','76.0.3809.12/','76.0.3809.126/','76.0.3809.25/','76.0.3809.68/','77.0.3865.10/','77.0.3865.40/','78.0.3904.105/','78.0.3904.11/','78.0.3904.70/','79.0.3945.16/','79.0.3945.36/',
'80.0.3987.106/','80.0.3987.16/','81.0.4044.138/','81.0.4044.20/','81.0.4044.69/','83.0.4103.14/','83.0.4103.39/','84.0.4147.30/','85.0.4183.38/','85.0.4183.83/','85.0.4183.87/','86.0.4240.22/','87.0.4280.20/']

核对版本信息

文本与列表核逐一对,需要遍历.由于版本号往往不是完全一致,并且实际也不需要完全一致,大概对的上就可以运行,所以定下规则

版本的前两处信息对得上就可以

目前是根据版本的那个.拆分为列表,核对列表的前两个元素

def compareVersion(chrome,driver):
    # 版本号的前两部分相等即为匹配
    # 返回核对后正确的完整版本号
    right_version = ''
    chrome_list = self.chrome.split('.')
    for ver in driver:
        _tmp = ver.split('.')
        if chrome_list[0] == _tmp[0] and chrome_list[1] == _tmp[1]:
            right_version = ver 
            break
    return right_version

ver = compareVersion(chrome,driver)

结果如下

>>> ver
'80.0.3987.106/'

版本号的前两处对得上就可以

下载文件

requestsget方法似乎是成功了,但是文件都不知道去哪了,还是得用一个能指定下载文件夹的方法

url_down = 'http://chromedriver.storage.googleapis.com/%schromedriver_win32.zip'
folder = r'c:\selenium_download'
FILE_NAME = 'chromedriver_win32.zip'

def downloadChromeDriver(version):
	# 下载,为了指定路径必须用urllib库
	# 返回下载文件路径
	from urllib.request import urlretrieve as urlrt
    url_download = url_down % version
	path_file = r'%s\%s' % (folder,FILE_NAME)
	urlrt(url_download,path_file)   # 已测试会自动覆盖
	return self.path_file

file = downloadChromeDriver(ver)
>>> file 
'c:\\selenium_download\\\chromedriver_win32.zip'

解压文件

FILE_EXE = 'chromedriver.exe'

def unzipFile(zip,folder):
	# 解压
	# 返回解压后的文件路径
	from zipfile import ZipFile as unzip
	cont = unzip(zip,'r')
	for file in cont.namelist():
	    cont.extract(file,folder)
	cont.close()
	driver_file = r'%s\%s' % (folder,FILE_EXE)
	return self.driver_file

exe = unzipFile(file,folder)
>>> exe
'c:\\selenium_download\\chromedriver.exe'

替换文件

将文件从Python的文件夹里面替换

  • 首先要获取Python安装路径
  • 删除原文件(如果已存在),移入新文件
def replaceDriverInPython(driver):
	import os
	import sys
	isdone = False
	# 替换Python Script文件夹里面的chromedriver
	# 在里面寻找Python路径,要求下级必须有Scripts文件夹,且路径末尾是Python关键字
	pypath = ''
	for path in sys.path:
	    if path.split('\\')[-1] == 'Python' and os.path.isdir(path):
	        for d in os.listdir(path):
	            if os.path.isdir(os.path.join(path,d)) and d == 'Scripts':
	                pypath = '%s\\%s' % (path,d)
	                break
	    if pypath != '':
	        break 
	
	if pypath != '':
	    dst_path = '%s\\%s' % (pypath,driver)
	    if os.path.isfile(dst_path):
	        os.remove(dst_path)
	    shutil.move(self.driver_file,pypath)
	    isdone = True
	else:
	    isdone = False
	
	return isdone

done = replaceDriverInPython(exe)
>>> done 
True

总结

需要用到的内部模块

import re		# 正则
import urllib	# 网络
import zipfile	# 压缩解压
import winreg	# windows注册表
import os		# 操作系统信息
import sys		# 设备信息
import shutil	# 文件操作

外部模块

import requests	# 用来获取网页源码

相关知识点

  • 正则
  • 爬虫

由于关乎到注册表,目前这段代码仅支持在Windows上运行

封装

'''
only for windows
'''

from requests import get 
from re import findall
from urllib.request import urlretrieve as urlrt
from zipfile import ZipFile as unzip
import winreg
import os
import sys
import shutil


URL = 'http://chromedriver.storage.googleapis.com/?delimiter=/&prefix='
REG = r'<Prefix>(\d.*?)</Prefix>'
FILE_NAME = 'chromedriver_win32.zip'
FILE_EXE = 'chromedriver.exe'
url_down = 'http://chromedriver.storage.googleapis.com/%schromedriver_win32.zip'


class sd_chrome():
    def __init__(self,_folder=r'c:\selenium_download'):
        # 防止文件夹路径不存在
        # 指定下载路径文件夹
        if not os.path.exists(_folder):
            os.makedirs(_folder)
        
        self.down_folder = _folder

    def getChromeVersion(self):
        # 从注册表获取chrome版本
        key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,r'Software\Google\Chrome\BLBeacon')
        self.chrome_version = winreg.QueryValueEx(key,'version')[0]
        return self.chrome_version
    
    def getChromeDriverVersionList(self):
        # 从网页源代码获取目前提供的版本号
        resp = get(URL)
        self.driver_version = findall(REG,resp.text) # 返回正则括号中结果的列表
        return self.driver_version

    def compareVersion(self):
        # 版本号的前两部分相等即为匹配
        self.right_version = ''
        chrome_version_list = self.chrome_version.split('.')
        for ver in self.driver_version:
            _tmp = ver.split('.')
            if chrome_version_list[0] == _tmp[0] and chrome_version_list[1] == _tmp[1]:
                self.right_version = ver 
                break
        return self.right_version
    
    def downloadChromeDriver(self):
        # 下载,为了指定路径必须用urllib库
        if self.right_version != '':
            url_download = url_down % self.right_version
            self.path_file = r'%s\%s' % (self.down_folder,FILE_NAME)
            urlrt(url_download,self.path_file)   # 已测试会自动覆盖
            print('已下载到:%s' % self.path_file)
            return self.path_file
        else:
            print('未获取到版本号,没有下载')

    def unzipFile(self):
        # 解压
        zip = unzip(self.path_file,'r')
        for file in zip.namelist():
            zip.extract(file,self.down_folder)
        zip.close()
        print('解压成功')
        self.driver_file = r'%s\%s' % (self.down_folder,FILE_EXE)
        return self.driver_file
    
    def replaceDriverInPython(self):
        isdone = False
        # 替换Python Script文件夹里面的chromedriver
        # 在里面寻找Python路径,要求下级必须有Scripts文件夹,且路径末尾是Python关键字
        pypath = ''
        for path in sys.path:
            if path.split('\\')[-1] == 'Python' and os.path.isdir(path):
                for d in os.listdir(path):
                    if os.path.isdir(os.path.join(path,d)) and d == 'Scripts':
                        pypath = '%s\\%s' % (path,d)
                        break
            if pypath != '':
                break 

        if pypath != '':
            dst_path = '%s\\%s' % (pypath,FILE_EXE)
            if os.path.isfile(dst_path):
                os.remove(dst_path)
            shutil.move(self.driver_file,pypath)
            isdone = True
        else:
            isdone = False
        
        return isdone

if __name__ == '__main__':
	down = r'c:\selenium_download'
	goo = sd_chrome(down)
	a = goo.getChromeVersion()
	b = goo.getChromeDriverVersionList()
	c = goo.compareVersion()
	d = goo.downloadChromeDriver()
	e = goo.unzipFile()
	f = goo.replaceDriverInPython()




1024,向程序员致敬∠(°ゝ°)

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

但老师

要是看起来爽 求打赏一耳光

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值