很多使用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總是不能及時兼容。有這類問題的你,還不趕緊動手試下?
歡迎掃碼關注我的公眾號 獲取更多爬蟲、數據分析的知識!