如何使用 Selenium Webdriver 和 Firefox 检测所有下载何时完成
How to detect when all downloads finished with Selenium Webdriver and Firefox
我有一个 FirefoxDriver 实例,它执行多个操作并开始下载多个文件。这些文件可能有不同的大小,当它完成循环并关闭时,它会中断未完成的下载。有没有一种方法可以检查是否有待处理的下载,然后等到它们全部完成后再关闭 Firefox Window?这是针对 VB.NET 但我也能理解 C# 解决方案。谢谢!
Firefox 和 Chrome 下载文件时会创建中间文件扩展名。对于 chrome,它是 crdownload,我不记得它对于 Firefox 是什么。但是,您可以下载一个大文件并进行检查。下载完成后,此中间文件将重命名为实际文件名。
您只需编写一段代码,检查是否存在任何带有 crdownload 扩展名的文件。如果没有,则您的下载已完成。
使用 Firefox,可以在浏览器级别注入一些 JavaScript,这意味着您几乎可以做任何事情。但是设置上下文的命令没有在 .Net 客户端中实现,所以你必须扩展 class.
此示例等待至少一次下载并等待所有下载成功,然后 returns 每个文件的完整路径:
var options = new FirefoxOptions();
options.SetPreference("browser.download.dir", "C:\temp");
options.SetPreference("pdfjs.disabled", true);
options.SetPreference("pdfjs.enabledCache.state", false);
options.SetPreference("browser.download.folderList", 2);
options.SetPreference("browser.download.useDownloadDir", true);
options.SetPreference("browser.helperApps.neverAsk.saveToDisk", "application/pdf");
var driver = new FirefoxDriverEx(options);
driver.Url = "https://support.mozilla.org/en-US/kb/use-adobe-reader-view-pdf-files-firefox";
driver.FindElementByCssSelector("[href*='mozilla_privacypolicy.pdf']").Click();
string[] files = driver.GetDownloads(1, TimeSpan.FromSeconds(120));
class FirefoxDriverEx : FirefoxDriver {
public FirefoxDriverEx(FirefoxOptions options) : base(options) {
var commands = CommandExecutor.CommandInfoRepository;
commands.TryAddCommand("SetContext", new CommandInfo("POST", "/session/{sessionId}/moz/context"));
}
public string[] GetDownloads(int minimum, TimeSpan timeout) {
const string JS_GET_DOWNLOADS = @"
var minimum = arguments[0], callback = arguments[1];
Components.utils.import('resource://gre/modules/Downloads.jsm', {}).Downloads
.getList(Downloads.ALL).then(list => list.getAll())
.then(items => items.length >= minimum && items.every(e => e.succeeded) ? items.map(e => e.target.path) : null)
.then(callback);";
try {
SetContext("chrome");
for (var endtime = DateTime.UtcNow + timeout; ; Thread.Sleep(1000)) {
Object result = ExecuteAsyncScript(JS_GET_DOWNLOADS, minimum);
if (result != null)
return ((IEnumerable<object>)result).Cast<string>().ToArray();
if (DateTime.UtcNow > endtime)
throw new TimeoutException("No download available or one is not complete.");
}
} finally {
SetContext("content");
}
}
public void SetContext(string context) {
var parameters = new Dictionary<string, object> { { "context", context } };
CommandExecutor.Execute(new Command(this.SessionId, "SetContext", parameters));
}
}
我有一个 FirefoxDriver 实例,它执行多个操作并开始下载多个文件。这些文件可能有不同的大小,当它完成循环并关闭时,它会中断未完成的下载。有没有一种方法可以检查是否有待处理的下载,然后等到它们全部完成后再关闭 Firefox Window?这是针对 VB.NET 但我也能理解 C# 解决方案。谢谢!
Firefox 和 Chrome 下载文件时会创建中间文件扩展名。对于 chrome,它是 crdownload,我不记得它对于 Firefox 是什么。但是,您可以下载一个大文件并进行检查。下载完成后,此中间文件将重命名为实际文件名。
您只需编写一段代码,检查是否存在任何带有 crdownload 扩展名的文件。如果没有,则您的下载已完成。
使用 Firefox,可以在浏览器级别注入一些 JavaScript,这意味着您几乎可以做任何事情。但是设置上下文的命令没有在 .Net 客户端中实现,所以你必须扩展 class.
此示例等待至少一次下载并等待所有下载成功,然后 returns 每个文件的完整路径:
var options = new FirefoxOptions();
options.SetPreference("browser.download.dir", "C:\temp");
options.SetPreference("pdfjs.disabled", true);
options.SetPreference("pdfjs.enabledCache.state", false);
options.SetPreference("browser.download.folderList", 2);
options.SetPreference("browser.download.useDownloadDir", true);
options.SetPreference("browser.helperApps.neverAsk.saveToDisk", "application/pdf");
var driver = new FirefoxDriverEx(options);
driver.Url = "https://support.mozilla.org/en-US/kb/use-adobe-reader-view-pdf-files-firefox";
driver.FindElementByCssSelector("[href*='mozilla_privacypolicy.pdf']").Click();
string[] files = driver.GetDownloads(1, TimeSpan.FromSeconds(120));
class FirefoxDriverEx : FirefoxDriver {
public FirefoxDriverEx(FirefoxOptions options) : base(options) {
var commands = CommandExecutor.CommandInfoRepository;
commands.TryAddCommand("SetContext", new CommandInfo("POST", "/session/{sessionId}/moz/context"));
}
public string[] GetDownloads(int minimum, TimeSpan timeout) {
const string JS_GET_DOWNLOADS = @"
var minimum = arguments[0], callback = arguments[1];
Components.utils.import('resource://gre/modules/Downloads.jsm', {}).Downloads
.getList(Downloads.ALL).then(list => list.getAll())
.then(items => items.length >= minimum && items.every(e => e.succeeded) ? items.map(e => e.target.path) : null)
.then(callback);";
try {
SetContext("chrome");
for (var endtime = DateTime.UtcNow + timeout; ; Thread.Sleep(1000)) {
Object result = ExecuteAsyncScript(JS_GET_DOWNLOADS, minimum);
if (result != null)
return ((IEnumerable<object>)result).Cast<string>().ToArray();
if (DateTime.UtcNow > endtime)
throw new TimeoutException("No download available or one is not complete.");
}
} finally {
SetContext("content");
}
}
public void SetContext(string context) {
var parameters = new Dictionary<string, object> { { "context", context } };
CommandExecutor.Execute(new Command(this.SessionId, "SetContext", parameters));
}
}