2009-07-17 8 views
5

Pracowałem nad programem WebCrawler napisanym w języku C# przy użyciu System.Windows.Forms.WebBrowser. Próbuję pobrać plik z witryny i zapisać go na komputerze lokalnym. Co ważniejsze, chciałbym, aby było to w pełni zautomatyzowane. Pobieranie pliku można rozpocząć, klikając przycisk wywołujący funkcję javascript, która uruchamia pobieranie wyświetlające okno dialogowe "Czy chcesz otworzyć lub zapisać ten plik?". Zdecydowanie nie chcę ręcznie klikać "Zapisz jako" i wpisywać nazwy pliku.Zautomatyzowane pobieranie plików za pomocą WebBrowser bez adresu URL

Jestem świadomy funkcji pobierania HttpWebRequest i WebClient, ale ponieważ pobieranie jest uruchamiane z javascript, teraz znam adres URL pliku. Fyi, javascript jest funkcją doPostBack, która zmienia niektóre wartości i przesyła formularz.

Próbowałem już skupić się na oknie dialogowym Zapisz jako z WebBrowser, aby zautomatyzować to z niego bez większego powodzenia. Wiem, że istnieje sposób na wymuszenie zapisu, aby zapisać, zamiast pytać o zapisanie lub otwarcie przez dodanie nagłówka do żądania http, ale nie wiem, jak określić ścieżkę do pliku do pobrania.

+0

Czy masz rozwiązanie Twoja ostatnia problem, jak pobrać plik, gdy jest on generowany w locie i nie można stwierdzić, że jest to plik pobrany z adresu URL? –

Odpowiedz

5

Myślę, że powinieneś uniemożliwić wyświetlanie okna dialogowego pobierania. Tutaj może być sposobem, aby to zrobić:

  • kod JavaScript powoduje, że sterowanie WebBrowser, aby przejść do określonego adresu URL (co powodowałoby okno Pobieranie pojawiać)

  • Aby zapobiec formantu WebBrowser z Właściwie Nawigowanie do tego adresu URL, dołączanie obsługi zdarzeń do zdarzenia nawigowania.

  • W swoim wydarzeniu nawigacyjnym musisz przeanalizować, czy jest to faktyczna akcja nawigacji, którą chcesz zatrzymać (czy jest to adres URL pobierania, być może sprawdź rozszerzenie pliku, musi być rozpoznawalny format) . Użyj narzędzia WebBrowserNavigatingEventArgs.Url, aby to zrobić.

  • Jeśli jest to właściwy adres URL, zatrzymaj nawigację, ustawiając właściwość WebBrowserNavigatingEventArgs.Anuluj.

  • kontynuować pobieranie się z HttpWebRequest lub WebClient klas

Wystarczy popatrzeć na tej stronie, aby uzyskać więcej informacji na temat imprezy:
http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.navigating.aspx

+1

Próbowałem już uzyskać adres URL za pomocą HttpDebugger, aby sprawdzić żądanie HTTP i odpowiedzi. Adres URL jest dokładnie taki sam, jeden jest żądaniem GET, a drugi jest żądaniem POST. Po prostu spróbowałem twojej sugestii bez powodzenia. – Sharath

+0

Możesz chcieć użyć kontrolki WebBrowser, aby dostać się do samego końca, tuż przed przesłaniem formularza, a następnie wyodrębnić miejsce docelowe POST formularza za pomocą DOM (uzyskaj odniesienie do treści dokumentu HTML i stamtąd udaj się do formularz). – Zyphrax

3

Podobne rozwiązanie jest dostępne w http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/d338a2c8-96df-4cb0-b8be-c5fbdd7c9202/?prof=required

Działa to doskonale, jeśli istnieje bezpośredni adres URL, w tym pobieranie nazwy pliku.

Ale czasami jakiś URL generuje plik dynamicznie. W związku z tym URL nie ma nazwy pliku, ale po zażądaniu tego adresu URL strona internetowa tworzy plik dynamicznie, a następnie otwiera się/zapisuje okno dialogowe.

Na przykład niektóre łącze generuje plik pdf w locie.

Jak obsługiwać tego typu URL?

1

Zakładając System.Windows.Forms.WebBrowswer użyto, aby uzyskać dostęp do strony chronionej z chronioną link, który chcesz pobrać:

Ten kod pobiera rzeczywisty związek chcesz pobrać, korzystając z internetu przeglądarka. Ten kod będzie musiał zostać zmieniony dla konkretnej akcji. Ważną częścią jest to pole documentLinkUrl, które zostanie użyte poniżej.

var documentLinkUrl = default(Uri); 
browser.DocumentCompleted += (object sender, WebBrowserDocumentCompletedEventArgs e) => 
{ 
    var aspForm = browser.Document.Forms[0]; 
    var downloadLink = browser.Document.ActiveElement 
     .GetElementsByTagName("a").OfType<HtmlElement>() 
     .Where(atag => 
      atag.GetAttribute("href").Contains("DownloadAttachment.aspx")) 
     .First(); 

    var documentLinkString = downloadLink.GetAttribute("href"); 
    documentLinkUrl = new Uri(documentLinkString); 
} 
browser.Navigate(yourProtectedPage); 

Po przejściu chronionej strony przez przeglądarkę internetową i uzyskaniu łącza do pobierania, kod ten pobiera łącze.

private static async Task DownloadLinkAsync(Uri documentLinkUrl) 
{ 
    var cookieString = GetGlobalCookies(documentLinkUrl.AbsoluteUri); 
    var cookieContainer = new CookieContainer(); 
    using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer }) 
    using (var client = new HttpClient(handler) { BaseAddress = documentLinkUrl }) 
    { 
     cookieContainer.SetCookies(this.documentLinkUrl, cookieString); 
     var response = await client.GetAsync(documentLinkUrl); 
     if (response.IsSuccessStatusCode) 
     { 
      var responseAsString = await response.Content.ReadAsStreamAsync(); 
      // Response can be saved from Stream 

     } 
    } 
} 

Powyższy kod opiera się na metodzie od Erika Chinchio GetGlobalCookies które można znaleźć w znakomitym artykule dostarczonych przez @Pedro Leonardo (dostępny here)

[System.Runtime.InteropServices.DllImport("wininet.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)] 
static extern bool InternetGetCookieEx(string pchURL, string pchCookieName, 
    System.Text.StringBuilder pchCookieData, ref uint pcchCookieData, int dwFlags, IntPtr lpReserved); 

const int INTERNET_COOKIE_HTTPONLY = 0x00002000; 

private string GetGlobalCookies(string uri) 
{ 
    uint uiDataSize = 2048; 
    var sbCookieData = new System.Text.StringBuilder((int)uiDataSize); 
    if (InternetGetCookieEx(uri, null, sbCookieData, ref uiDataSize, 
      INTERNET_COOKIE_HTTPONLY, IntPtr.Zero) 
     && 
     sbCookieData.Length > 0) 
    { 
     return sbCookieData.ToString().Replace(";", ","); 
    } 
    return null; 
} 
Powiązane problemy