Selenium:在 Internet Explorer 中下载文件到指定文件夹,无需直接链接,无需 Windows Forms,无需 AutoIt 或 Robot [英] Selenium: download file in Internet Explorer to specified folder without direct link, without Windows Forms, without AutoIt or Robot

查看:21
本文介绍了Selenium:在 Internet Explorer 中下载文件到指定文件夹,无需直接链接,无需 Windows Forms,无需 AutoIt 或 Robot的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经常遇到一个问题,如何在 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、使用键盘命令、Robot 等……但所有这些选项都不稳定,它们需要显式等待、使用冗余库,并且不适合并行运行测试.另一个问题是,如果文件不是通过直接链接下载的,而是从 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.

所有这些问题都可以解决,在 hte answer 中,我将展示如何去做.解决方案是用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 将下载文件到指定的文件路径(文件夹 + 文件名),例如DownloadFileExplore("C:my_folder eport.xslx")

Method DownloadFileIexplore will download file to the specified filePath (folder + filename), e.g. DownloadFileExplore("C:my_folder eport.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 Forms,无需 AutoIt 或 Robot的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆