问题描述
我经常遇到一个问题,如何在IE中下载文件。
与Firefox的Chrome相比,您不仅可以指定所需的文件夹,而且所有文件都将下载到该文件夹。您还需要与本机Windows窗体等进行交互。
I've often faced an issue, how to download files in IE.In contrast to Chrome of Firefox, you cannot just specify required folder, and all the files will be downloaded to that folder. You also need to interact with native Windows forms and so on.
有多个选项,例如使用AutoIt,使用键盘命令,机器人等等......但所有这些选项不稳定,它们需要使用冗余库进行显式等待,并且在并行运行测试时不合适。另一个问题是,该怎么办,如果文件没有通过直接链接下载,但链接是从javascript命令生成或从服务器接收,并且无法从html中提取。
There are multiple options, like using AutoIt, using keyboard commands, Robot and etc... But all this options aren't stable, they require explicit waiting, using redundant libraries, and non-appropriate when run tests in parallel. The other problem, is what to do, if the file isn't downloaded by direct link, but link is generated from javascript command or received from server, and cannot be extracted from html.
所有这些问题都可以解决,在这里我会说明如何做到这一点。
解决方案是用c#编写的,我相信同样可以在java中实现
All these problems can be solved, here in hte answer i'll show how to do it.Solution is written in c#, i believe the same can be implemented in java
推荐答案
方法DownloadFileIexplore会将文件下载到指定的filePath(文件夹+文件名),例如DownloadFileExplore(C:\ my_folder \ renport.xslx)
Method DownloadFileIexplore will download file to the specified filePath (folder + filename), e.g. DownloadFileExplore("C:\my_folder\report.xslx")
public void DownloadFileIexplore(string filePath)
{
//Click the link.
//Simple click can be used instead, but in my case it didn't work for all the links, so i've replaced it with click via action:
new Actions(Browser.Driver).MoveToElement(Element).Click(Element).Perform();
//Different types of element can be used to download file.
//If the element contains direct link, it can be extracter from 'href' attribute.
//If the element doesn't contains href or it's just an javascript command, link will be extracted from the browser http requests.
//
string downloadUrlOrLink = Element.GetAttribute("href") != null && !Element.GetAttribute("href").Contains("javascript")
? Element.GetAttribute("href")
: GetRequestUrls().Last() ?? GetLinkInNewWindowIexplore();
if (downloadUrlOrLink == null)
{
throw Log.Exception("Download url cannot be read from the element href attribute and from the recent http requests.");
}
/// the last step is to download file using CookieWebClient
/// method DownloadFile is available in the System.Net.WebClient,
/// but we have to create new class CookieWebClient, that will be inherited from System.Net.WebClient with one overriden method
new CookieWebClient(GetCookies()).DownloadFile(downloadUrlOrLink, filePath);
}
/// <summary>
/// this method returns all the http requests sent from browser.
/// the latest requests was send when link (or button) was clicked to download file
/// so we will need just to get last element from list: GetRequestUrls().Last().
/// or, if the request for file downloading isn't the last, find the required request by part of url, in my case it was 'common/handler', e.g.:
/// GetRequestUrls().LastOrDefault(x => x.Contains("common/handler"))
/// <summary>
public List<string> GetRequestUrls()
{
ReadOnlyCollection<object> requestsUrls = (ReadOnlyCollection<object>)
Driver.ExecuteScript("return window.performance.getEntries().map(function(x) { return x.name });");
return requestsUrls.Select(x => (string) x).ToList();
}
/// <summary>
/// In some cases after clicking the Download button new window is opened in IE.
/// Driver.WindowHandles can return only one window instead of two.
/// To solve this problem reset IE security settings and set Enable Protected Mode for each zone.
/// </summary>
private string GetLinkInNewWindowIexplore()
{
/// here it would be better to add waiting till new window is opened.
/// in that case we have to calculate number of windows before click and send this number as argument to GetLinkInNewWindowIexplore()
/// and wait till number will be increased by 1
var availableWindows = Driver.WindowHandles;
if (availableWindows.Count > 1)
{
Driver.SwitchTo().Window(availableWindows[availableWindows.Count - 1]);
}
string url;
try
{
url = Driver.Url;
}
catch (Exception)
{
url = Driver.ExecuteScript("return document.URL;").ToString();
}
Driver.SwitchTo().Window(Driver.WindowHandles[0]);
return url;
}
public System.Net.CookieContainer GetCookies()
{
CookieContainer cookieContainer = new CookieContainer();
foreach (OpenQA.Selenium.Cookie cookie in Driver.Manage().Cookies.AllCookies)
{
cookieContainer.Add(new System.Net.Cookie
{
Name = cookie.Name,
Value = cookie.Value,
Domain = "domain of your site, you can find, track http requests send from your site in browser dev tools, tab Network"
});
}
return cookieContainer;
}
public class CookieWebClient : WebClient
{
private readonly CookieContainer _cookieContainer;
public CookieWebClient(CookieContainer cookieContainer)
{
_cookieContainer = cookieContainer;
}
/// it's necessary to override method to add cookies, because file cannot be download by non-authorized user
/// ServerCertificateValidationCallback is set to true to avoid some possible certificate errors
protected override WebRequest GetWebRequest(Uri address)
{
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
WebRequest request = base.GetWebRequest(address);
HttpWebRequest webRequest = request as HttpWebRequest;
if (webRequest != null)
{
webRequest.CookieContainer = _cookieContainer;
}
return request;
}
}
这篇关于Selenium:将Internet Explorer中的文件下载到没有直接链接的指定文件夹,没有Windows窗体,没有AutoIt或Robot的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!