时不时地更新Chrome,脚本中使用的现有chrome驱动程序变得无效,并显示以下错误消息:

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


我必须手动更新书面脚本中的chrome驱动程序。有什么方法可以使用更新的chrome版本自动更新它吗?

评论

您使用哪种依赖性管理工具?

当前未使用任何依赖工具。我正在用Python编写脚本。你能提到任何可以使用的工具吗?

#1 楼

尝试从npm使用webdriver-manager:

https://www.npmjs.com/package/webdriver-manager

,然后使用Java,Python中的批处理文件调用webdriver-manager update或任何一种工具。

要创建批处理文件,请打开一个文本文件并添加webdriver-manager update作为内容,然后将其另存为file.bat

#2 楼

是的,可以做到。您需要执行以下步骤,并且需要选择一种用于实现它们的工具。
让我们看一下Python中的几行内容,我将概述主要流程,并且您可能希望对其进行更多构建功能强大(例如命令行参数等)。
首先,我将导入requests
 import requests
 

然后我将将必要的链接保存到两个变量中+我定义了所需版本的chrome驱动程序的文件名:
 url = 'https://chromedriver.storage.googleapis.com/LATEST_RELEASE_'
url_file = 'https://chromedriver.storage.googleapis.com/'
file_name = 'chromedriver_linux64.zip'
 

现在我' ll让用户选择一个版本,然后从网站上获取该版本:
 version = input()
version_response = requests.get(url + version)
 

最后,是时候下载zip文件(如果存在):
 if version_response.text:
    file = requests.get(url_file + version_response.text + '/' + file_name)
    with open(file_name, "wb") as code:
        code.write(file.content)
 

这些步骤的结果将是一个带有chrome驱动程序的zip文件。当前目录(运行脚本的位置)。成功下载后,还可以使用zipfile库提取zip文件。
如果要完全自动化,则可能需要内置命令行参数并将chrome版本通过管道传递到Python脚本中。例如。在类似Arch的系统中,您可以使用$ pacman -Qs chromium获得Chromium版本。由于您没有提到要在其上构建的系统体系结构,因此我选择了我的系统。
准备好后,可以让它与cron或类似的软件一起运行。

#3 楼

使用WebdriverManage。它将所需的驱动程序二进制文件(如果本地不存在)下载到缓存(默认位置〜/ .m2 / repository / webdriver)中。这是将其添加到代码中的方法:

WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();


最新版本依赖项:

<!-- https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager -->
<dependency>
    <groupId>io.github.bonigarcia</groupId>
    <artifactId>webdrivermanager</artifactId>
    <version>3.7.1</version>
</dependency>


#4 楼

一种适用于您要自动化的任何编程语言的解决方案。这样,您的团队可以使用任何Selenium工具实现自动化。
使用Docker,您可以运行自己的WebDriverManager服务器,然后您要做的就是编写非常简单的代码以从中下载驱动程序:
# Mac OSX command
docker run -p 4041:4041 -v $HOME/wdm:/root/.m2/repository bonigarcia/webdrivermanager:4.0.0

# Windows command
docker run -p 4041:4041 -v %USERPROFILE%/wdm:/root/.m2/repository bonigarcia/webdrivermanager:4.0.0

驱动程序将存储在本地$ HOME / wdm文件夹中,以及docker镜像中。在Docker中,将其设置为通过自动重启策略保持守护进程状态。在AWS或Azure上托管此服务非常便宜,因为它只需要最少的硬件即可运行它。
这是查询服务的样子(使用Insomnia rest客户端):
> GET /firefoxdriver?os=LINUX HTTP/1.1
> Host: localhost:4041
> User-Agent: insomnia/7.1.1
> Accept: */*

< HTTP/1.1 200 OK
< Date: Sat, 04 Jul 2020 17:56:07 GMT
< Server: Javalin
< Content-Type: text/plain
< Content-Disposition: attachment; filename="geckodriver"
< Transfer-Encoding: chunked


* Received 15.8 KB chunk
* Received 15.6 KB chunk
  ....

注意:我真的很喜欢这个解决方案,但是当涉及到它时,我可能更喜欢使用Aerokube dockerized浏览器容器实现自动化,例如使用“ Moon framework”,它的价格仅为$ 5 /线程/月运行dockerized浏览器测试的Selenium网格。

#5 楼

首先,@ Asyranok是正确的,即使已实现的自动更新代码在100%的时间内都无法正常工作。但是,对于我们许多人来说,偶尔的停机时间只要几天就可以了。
我发现,每隔几个月手动更新X个服务器会令人难以置信,而且写得很好在有关如何“自动更新”驱动程序的硒网站上,我尚未看到该指南的一个公开可用的非库实现。
我的回答特定于C#,对于这种语言,通常建议的解决方案是使用NuGet自动拉动最新的驱动程序,这有两个问题:


您需要以chrome更新的频率进行部署(大多数公司都还没有,我们也不是)或在chrome更新和部署应用程序的“新”版本之间,您的应用程序将被“破坏”,同样,这仅在按计划发布,临时发布的情况下才需要进行。一系列手动步骤进行更新,构建,发布等,以使您的应用程序再次运行。


您需要(通常没有任何解决方法)从NuGet手动拉出最新的chromedrive,再次手动进行操作。


python和@leminhnguyenHUST应该是什么建议使用哪个库,该库会在运行时自动提取最新的chromedriver。我环顾四周,还没有找到任何可用于C#的东西,所以我决定将自己的东西放进我的应用程序中:
public void DownloadLatestVersionOfChromeDriver()
{
    string path = DownloadLatestVersionOfChromeDriverGetVersionPath();
    var version = DownloadLatestVersionOfChromeDriverGetChromeVersion(path);
    var urlToDownload = DownloadLatestVersionOfChromeDriverGetURLToDownload(version);
    DownloadLatestVersionOfChromeDriverKillAllChromeDriverProcesses();
    DownloadLatestVersionOfChromeDriverDownloadNewVersionOfChrome(urlToDownload);
}

public string DownloadLatestVersionOfChromeDriverGetVersionPath()
{
    //Path originates from here: https://chromedriver.chromium.org/downloads/version-selection            
    using (RegistryKey key = Registry.LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe"))
    {
        if (key != null)
        {
            Object o = key.GetValue("");
            if (!String.IsNullOrEmpty(o.ToString()))
            {
                return o.ToString();
            }
            else
            {
                throw new ArgumentException("Unable to get version because chrome registry value was null");
            }
        }
        else
        {
            throw new ArgumentException("Unable to get version because chrome registry path was null");
        }
    }
}

public string DownloadLatestVersionOfChromeDriverGetChromeVersion(string productVersionPath)
{
    if (String.IsNullOrEmpty(productVersionPath))
    {
        throw new ArgumentException("Unable to get version because path is empty");
    }

    if (!File.Exists(productVersionPath))
    {
        throw new FileNotFoundException("Unable to get version because path specifies a file that does not exists");
    }

    var versionInfo = FileVersionInfo.GetVersionInfo(productVersionPath);
    if (versionInfo != null && !String.IsNullOrEmpty(versionInfo.FileVersion))
    {
        return versionInfo.FileVersion;
    }
    else
    {
        throw new ArgumentException("Unable to get version from path because the version is either null or empty: " + productVersionPath);
    }
}

public string DownloadLatestVersionOfChromeDriverGetURLToDownload(string version)
{
    if (String.IsNullOrEmpty(version))
    {
        throw new ArgumentException("Unable to get url because version is empty");
    }

    //URL's originates from here: https://chromedriver.chromium.org/downloads/version-selection
    string html = string.Empty;
    string urlToPathLocation = @"https://chromedriver.storage.googleapis.com/LATEST_RELEASE_" + String.Join(".", version.Split('.').Take(3));

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlToPathLocation);
    request.AutomaticDecompression = DecompressionMethods.GZip;

    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    using (Stream stream = response.GetResponseStream())
    using (StreamReader reader = new StreamReader(stream))
    {
        html = reader.ReadToEnd();
    }

    if (String.IsNullOrEmpty(html))
    {
        throw new WebException("Unable to get version path from website");
    }

    return "https://chromedriver.storage.googleapis.com/" + html + "/chromedriver_win32.zip";
}

public void DownloadLatestVersionOfChromeDriverKillAllChromeDriverProcesses()
{
    //It's important to kill all processes before attempting to replace the chrome driver, because if you do not you may still have file locks left over
    var processes = Process.GetProcessesByName("chromedriver");
    foreach (var process in processes)
    {
        try
        {
            process.Kill();
        }
        catch
        {
            //We do our best here but if another user account is running the chrome driver we may not be able to kill it unless we run from a elevated user account + various other reasons we don't care about
        }
    }
}

public void DownloadLatestVersionOfChromeDriverDownloadNewVersionOfChrome(string urlToDownload)
{
    if (String.IsNullOrEmpty(urlToDownload))
    {
        throw new ArgumentException("Unable to get url because urlToDownload is empty");
    }

    //Downloaded files always come as a zip, we need to do a bit of switching around to get everything in the right place
    using (var client = new WebClient())
    {
        if (File.Exists(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\chromedriver.zip"))
        {
            File.Delete(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\chromedriver.zip");
        }

        client.DownloadFile(urlToDownload, "chromedriver.zip");

        if (File.Exists(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\chromedriver.zip") && File.Exists(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\chromedriver.exe"))
        {
            File.Delete(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\chromedriver.exe");
        }

        if (File.Exists(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\chromedriver.zip"))
        {
            System.IO.Compression.ZipFile.ExtractToDirectory(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "\chromedriver.zip", System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
        }
    }
}

然后通常我会坚持使用这个非常hacky在我的应用程序开始时调用来调用此功能,并确保最新的chromedriver可用于我的应用程序:
//This is a very poor way of determining if I "need" to update the chromedriver,     
//however I've yet to figure out a better way of doing this...
try
{
    using (var chromeDriver = SetupChromeDriver())
    {
        chromeDriver.Navigate().GoToUrl("www.google.com");
        chromeDriver.Quit();
    }
}
catch
{
    DownloadLatestVersionOfChromeDriver();
}

我敢肯定,这可以得到很大的改善,但是到目前为止,它对我来说是有效的。
注意:十字张贴在这里

#6 楼

使用软件包的最佳方法

chromedriver-autoinstaller

对我来说很完美。我会定期使用一些自动化脚本来创建报告。
请查看文档以了解更多详细信息。
https://pypi.org/project/chromedriver-autoinstaller/