Скачивание файла с помощью Watin в IE9

У меня проблема с автоматизацией процесса загрузки файла с веб-сайта. На веб-сайте есть кнопка Java, которая при нажатии запускает загрузку файла Excel. Я использую самую последнюю сборку Watin (v2.1).

Мне удалось заставить Ватина зайти на сайт, перейти на соответствующую страницу, изменить параметры на странице и нажать кнопку, чтобы начать загрузку.

Однако после завершения загрузки появляется окно загрузки IE9, и ничего не происходит, пока не истечет тайм-аут Watin.

Буду признателен за любые предложения, так как я не вижу способа загрузить файл или получить его, чтобы сохранить файл. Даже если он передаст "Alt+S" на страницу, это сохранит его. Я попытался запустить его через WatinTestRecorder, и это не требует сохранения.

using (var browser = new IE(sLogin))
{
    browser.AddDialogHandler(new OKDialogHandler());
    browser.AddDialogHandler(new DialogHandlerHelper());
    browser.AddDialogHandler(new ConfirmDialogHandler());
    browser.AddDialogHandler(new ReturnDialogHandlerIe9());

    browser.TextField(Find.ByName("txtUserID")).TypeText("username");
    browser.TextField(Find.ByName("txtPassword")).TypeText("password");
    browser.Button(Find.ByName("btnLogin")).Click();

    browser.WaitForComplete();  
    browser.GoTo(targetUri);

    browser.SelectList("ctl00_phFormContent_ucOptionParam0_lst").SelectByValue("4");

    browser.Button(Find.ByName("ctl00$phFormButtonBar$btnRun")).Click();
    browser.WaitForComplete();

    //Some code to download the file here!
}

5 ответов

Решение

Это должно поддерживаться начиная с версии 1.1.0.4000. Примечания к выпуску этой версии больше не доступны ( http://watin.org/documentation/), но я нашел ее в кеше Googles ( http://svn6.assembla.com/svn/ci-samples/dotnet/watir/website/releasenotes-1-1-0-4000.html)

Это должно быть что-то вроде:

using(IE ie = new IE(someUrlToGoTo))
{
    FileDownloadHandler fileDownloadHandler = new FileDownloadHandler(fullFileName);
    ie.AddDialogHandler(fileDownloadHandler);

    ie.Link("startDownloadLinkId").Click();

    fileDownloadHandler.WaitUntilFileDownloadDialogIsHandled(15);
    fileDownloadHandler.WaitUntilDownloadCompleted(200);
}

РЕДАКТИРОВАТЬ: После комментариев ниже, этот ответ был принят. Поэтому я предполагаю, что работает следующий код (который взят из ссылки на SourceForge в моем последнем комментарии, обратите внимание на ClickNoWait):

using(IE ie = new IE(someUrlToGoTo))
{
    FileDownloadHandler fileDownloadHandler = new FileDownloadHandler(fullFileName);
    ie.AddDialogHandler(fileDownloadHandler);

    ie.Link("startDownloadLinkId").ClickNoWait();

    fileDownloadHandler.WaitUntilFileDownloadDialogIsHandled(15);
    fileDownloadHandler.WaitUntilDownloadCompleted(200);
}

Принятый ответ не сработал для меня, потому что в IE 9 появляется "Уведомление", по которому нужно перейти, прежде чем вы сможете перейти к реальному диалоговому окну "Сохранить как" (а WatiN не может обрабатывать уведомления автоматически). Я перешел по ссылке Борриса Павлова, который хорошо показал дорогу. Я немного очистил код, который был размещен там, и это был полученный файл:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WatiN.Core;
using WatiN.Core.Native.Windows;
using System.Threading;
using System.Windows.Automation;

namespace MyProject
{
    public static class BrowserExtensionMethods
    {
        public static void DownloadIeFile(this IE browser,string saveAsFilename=null)
        {
            // see information here (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515(v=vs.85).aspx)
            Window windowMain = new Window(NativeMethods.GetWindow(browser.hWnd, 5));
            TreeWalker dialogElementTreeWalker = new TreeWalker(Condition.TrueCondition);
            AutomationElement mainWindow = dialogElementTreeWalker.GetParent(AutomationElement.FromHandle(browser.hWnd));

            Window windowDialog = new Window(NativeMethods.GetWindow(windowMain.Hwnd, 5));
            // if doesn't work try to increase sleep interval or write your own waitUntill method
            Thread.Sleep(1000);
            windowDialog.SetActivate();
            AutomationElementCollection dialogElements = AutomationElement.FromHandle(windowDialog.Hwnd).FindAll(TreeScope.Children, Condition.TrueCondition);

            if (string.IsNullOrEmpty(saveAsFilename))
            {
                ClickSave(dialogElements);
            }
            else
            {
                ClickSaveAs(mainWindow, dialogElements,saveAsFilename);
            }
        }

        private static void ClickSaveAs(AutomationElement mainWindow, AutomationElementCollection dialogElements,string filename)
        {
            foreach (AutomationElement element in dialogElements)
            {

                if (element.Current.Name.Equals("Save"))
                {
                    AutomationElementCollection dialogSubElements = element.FindAll(TreeScope.Children, Automation.ControlViewCondition);
                    InvokePattern clickPatternForSaveDropdown = (InvokePattern)dialogSubElements[0].GetCurrentPattern(AutomationPattern.LookupById(10000));
                    clickPatternForSaveDropdown.Invoke();
                    Thread.Sleep(3000);

                    AutomationElementCollection dialogElementsInMainWindow = mainWindow.FindAll(TreeScope.Children, Condition.TrueCondition);
                    foreach (AutomationElement currentMainWindowDialogElement in dialogElementsInMainWindow)
                    {
                        if (currentMainWindowDialogElement.Current.LocalizedControlType == "menu")
                        {
                            // first array element 'Save', second array element 'Save as', third second array element    'Save and open'
                            InvokePattern clickMenu = (InvokePattern)currentMainWindowDialogElement.FindAll(TreeScope.Children, Condition.TrueCondition)[1].GetCurrentPattern(AutomationPattern.LookupById(10000));
                            clickMenu.Invoke();
                            Thread.Sleep(5000);
                            ControlSaveDialog(mainWindow, filename);
                            break;

                        }
                    }
                }
            }
        }

        private static void ClickSave(AutomationElementCollection dialogElements)
        {
            foreach (AutomationElement element in dialogElements)
            {
                // You can use "Save ", "Open", ''Cancel', or "Close" to find necessary button Or write your own enum
                if (element.Current.Name.Equals("Save"))
                {
                    // if doesn't work try to increase sleep interval or write your own waitUntil method
                    // WaitUntilButtonExsist(element,100);
                    Thread.Sleep(1000);
                    AutomationPattern[] automationPatterns = element.GetSupportedPatterns();
                    // replace this foreach if you need 'Save as' with code bellow
                    foreach (AutomationPattern currentPattern in automationPatterns)
                    {
                        // '10000' button click event id 
                        if (currentPattern.Id == 10000)
                        {
                            InvokePattern click = (InvokePattern)element.GetCurrentPattern(currentPattern);
                            click.Invoke();
                        }
                    }
                }
            }
        }

        private static void ControlSaveDialog(AutomationElement mainWindow, string path)
        {
            //obtain the save as dialog
            //*** must disable throwing of the NonComVisibleBaseClass "exception" for this to work in debug mode:
            //              1. Navigate to Debug->Exceptions...
            //              2. Expand "Managed Debugging Assistants"
            //              3. Uncheck the NonComVisibleBaseClass Thrown option.
            //              4. Click [Ok]
            //***copied from http://social.msdn.microsoft.com/Forums/en-US/27c3bae8-41fe-4db4-8022-e27d333f714e/noncomvisiblebaseclass-was-detected?forum=Vsexpressvb

            var saveAsDialog = mainWindow.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Save As"));
            //var saveAsDialog = mainWindow.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "[#] Save As [#]"));  //needed if using sandboxie
            //get the file name box
            var saveAsText = saveAsDialog
                    .FindFirst(TreeScope.Descendants,
                               new AndCondition(
                                   new PropertyCondition(AutomationElement.NameProperty, "File name:"),
                                   new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)))
                    .GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
            //fill the filename box 
            saveAsText.SetValue(path);

            Thread.Sleep(1000);
            //find the save button
            var saveButton =
                    saveAsDialog.FindFirst(TreeScope.Descendants,
                    new AndCondition(
                        new PropertyCondition(AutomationElement.NameProperty, "Save"),
                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)));
            //invoke the button
            var pattern = saveButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
            pattern.Invoke();
        }
    }
}

См. Комментарий в методе ControlSaveDialog для получения информации о том, как заставить эту работу работать как отладочная сборка (настройки VS).

Я на самом деле только протестировал операцию "Сохранить как", поэтому я надеюсь, что другие работы (кажется, что оригинальный постер добавил "Сохранить как" в качестве запоздалой мысли, так что я предполагаю, что он проверил операцию "Сохранить" более тщательно).

Чтобы вызвать это, вы можете использовать такой код:

Link lastMp4Link = mp4Links[mp4Links.Count - 1];  //mp4Links is a WatiN.Core.LinkCollection
lastMp4Link.Click();

browser.DownloadIeFile(string.Format(@"c:\temp\myFile.blah"));  //"browser" is a WatiN.Core.IE object

Я только что получил сообщение из списка рассылки пользователей Watin, что FileDownloadHandler не работает с IE9. Исправления пока нет, однако я удалил IE9 (откат к IE8), и у него есть диалог старого стиля, который обрабатывается WatiN.

Watin не может найти диалог загрузки и кнопки диалога. Это может решить с этим.

Как проверить загрузку файла с помощью Watin / IE9?

Смотрите комментарии

После многих ревизий с использованием WaitN я в конечном итоге использовал Selenium. Это дает вам больший контроль над тем, что обрабатывается и используется, и позволяет вам использовать более современные веб-браузеры.

Другие вопросы по тегам