Скачивание файла с помощью 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. Это дает вам больший контроль над тем, что обрабатывается и используется, и позволяет вам использовать более современные веб-браузеры.