First @Asyranok is right,即使实现了自动更新代码也不会 100% 工作。但是,对于我们中的许多人来说,这种偶尔的停机时间是“可以的”,只要它只是几天。
我发现每隔几个月手动更新 X 服务器非常令人恼火,虽然 selenium 网站上有 well written instructions 关于如何“自动更新”驱动程序,但我还没有看到一个公开可用的非本指南的库实现。
我的回答是针对 C# 的,对于这种语言,通常建议的解决方案是 use NuGet 自动拉取最新的驱动程序,这有两个问题:
-
您需要按照 chrome 更新的频率进行部署(大多数公司还没有,我们也没有),否则您的应用程序将在 chrome 更新和应用程序的“新”版本部署之间的时间里“损坏” ,而且这只是在您按计划发布的情况下,如果您临时发布,您将不得不通过一系列手动步骤来更新、构建、发布等,以使您的应用程序再次运行。
-
您需要(通常是without a work around)手动从 NuGet 中提取最新的 chromedrive,这也是一个手动过程。
python 所拥有的和 @leminhnguyenHUST suggests 使用的库会在运行时自动拉取最新的 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();
}
我确信这可以得到显着改善,但到目前为止它对我有用。
注意:交叉发布Here