java - Selenium:在没有直接链接、没有 Windows 窗体、没有 AutoIt 或 Robot 的情况下,将 Internet Explorer 中的文件下载到指定文件夹

标签 java c# selenium internet-explorer download

我经常遇到一个问题,如何在 IE 中下载文件。 与 Firefox 的 Chrome 不同,您不能只指定所需的文件夹,所有文件都会下载到该文件夹​​。您还需要与 native Windows 窗体等进行交互。

有多种选择,例如使用 AutoIt、使用键盘命令、Robot 等...但所有这些选项都不稳定,它们需要显式等待,使用冗余库,并且在并行运行测试时不合适。另一个问题是,如果文件不是通过直接链接下载的,但是链接是从 javascript 命令生成的或从服务器接收的,并且无法从 html 中提取,该怎么办。

所有这些问题都可以解决,在hte answer中我将展示如何去做。 解决方案是用c#写的,我相信同样可以用java实现

最佳答案

DownloadFileIexplore 方法将文件下载到指定的文件路径(文件夹+文件名),例如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;
    }
}

关于java - Selenium:在没有直接链接、没有 Windows 窗体、没有 AutoIt 或 Robot 的情况下,将 Internet Explorer 中的文件下载到指定文件夹,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48240146/

相关文章:

java多个对象作为函数的参数

java - 如何定位文件?

ruby-on-rails - 如何在带有 Selenium 的 Capybara 中使用 ruby​​-debug

java - 使用 CDI 机制替换基于工厂的对象创建

Java 并发数 : executing many "infinite" tasks with few threads

c# - 为什么我不能从机器外部访问我的 WCF 服务,但我可以在本地访问?

c# - 根据嵌套数组内的条件选择对象

javascript - 将 javascript 日期转换为 C# 日期时间

javascript - 在 Selenium 中点击 JavaScript 按钮 - Java

java - 如何在 Selenium Webdriver (JAVA) 中使用 "extends"