python selenium之chromedriver与chrome版本匹配问题(二)
很多使用selenium的用户都会遇到一个问题,我们的chromedriver经常与本地的chrome浏览器版本不兼容,导致我们实例化webdriver.Chrome失败,错误信息大致如下:
小爬在之前的博文中(python selenium自动化之chrome与chromedriver版本兼容问题),封装了方法来分别获取chrome版本和chromedriver版本,当两者版本的主版本号存在差异时,自动联网在淘宝源仓库:ChromeDriver Mirror (taobao.org)中下载对应的版本chromedriver,实现chromedriver基于需求的自动更新,使得两者能长期匹配。
实际上经过一番摸索,小爬发现有第三方的专业python库webdriver_manager优雅地解决了这一问题,且其后台更新chromedriver使用的是谷歌官方的chromedriver仓库。该URL(http://chromedriver.storage.googleapis.com/index.html)在国内是可以正常访问的,相对于淘宝源仓库最大的优势是,它永远存有chrome最新版的chromedriver,仓库更新的频率更快,如下图所示:
实际上,webdriver-manager库(通过pip install webdriver-manager安装即可)也可以用来更新EdgeChromiumDriver、GeckoDriver、IEDriver、OperaDriver文件,具体如何操作呢,其实我们执行时就两三行代码:
driver_path=ChromeDriverManager().install()
driver = webdriver.Chrome(executable_path=driver_path)
当然,我们如果多具备些探究竟精神,不妨看下其源码,了解其精髓。其中ChromeDriverManager类的源码如下:
class ChromeDriverManager(DriverManager): def __init__(self, version="latest", os_type=utils.os_type(), path=None, name="chromedriver", url="https://chromedriver.storage.googleapis.com", latest_release_url="https://chromedriver.storage.googleapis.com/LATEST_RELEASE", chrome_type=ChromeType.GOOGLE, log_level=logging.INFO, print_first_line=True, cache_valid_range=1): super().__init__(path, log_level=log_level, print_first_line=print_first_line, cache_valid_range=cache_valid_range) self.driver = ChromeDriver(name=name, version=version, os_type=os_type, url=url, latest_release_url=latest_release_url, chrome_type=chrome_type) def install(self): log(f"Current {self.driver.chrome_type} version is {self.driver.browser_version}", first_line=True) driver_path = self._get_driver_path(self.driver) os.chmod(driver_path, 0o755) return driver_path
chromedriver类的源码如下:
class ChromeDriver(Driver): def __init__(self, name, version, os_type, url, latest_release_url, chrome_type=ChromeType.GOOGLE): super(ChromeDriver, self).__init__(name, version, os_type, url, latest_release_url) self.chrome_type = chrome_type self.browser_version = get_browser_version_from_os(chrome_type) def get_os_type(self): if "win" in super().get_os_type(): return "win32" return super().get_os_type() def get_latest_release_version(self): log(f"Get LATEST driver version for {self.browser_version}") resp = requests.get(f"{self._latest_release_url}_{self.browser_version}") validate_response(resp) return resp.text.rstrip()
该方法会默认调用DriverCache类的find_driver方法:
def find_driver(self, browser_version, driver_name, os_type, driver_version): metadata = self.get_metadata() key = f"{os_type}_{driver_name}_{driver_version}_for_{browser_version}" if key not in metadata: log(f"There is no [{os_type}] {driver_name} for browser {browser_version} in cache") return None driver_info = metadata[key] if not self.__is_valid(driver_info): return None path = driver_info['binary_path'] log(f"Driver [{path}] found in cache") return path
如果系统能在特定路径下找到对应版本的driver,则可以直接调用,否则调用get_latest_release_version方法来联网获取最新的driver,并放在对应的系统路径下,比如我电脑上chromedriver最新版统一存储在下图所示路径下,供参考:
因电脑端chrome浏览器自动升级策略,导致本地的chromedriver总是不能及时兼容。有这类问题的你,还不赶紧动手试下?
欢迎扫码关注我的公众号 获取更多爬虫、数据分析的知识!