2009-07-17 47 views
5

He estado trabajando en un WebCrawler escrito en C# usando System.Windows.Forms.WebBrowser. Intento descargar un archivo de un sitio web y guardarlo en una máquina local. Más importante aún, me gustaría que esto esté completamente automatizado. La descarga del archivo se puede iniciar haciendo clic en un botón que llama a una función de JavaScript que activa la descarga y muestra el cuadro de diálogo "¿Desea abrir o guardar este archivo?". Definitivamente no quiero hacer clic manualmente en "Guardar como" y escribir el nombre del archivo.Descarga automatizada de archivos usando WebBrowser sin url

Conozco las funciones de descarga de HttpWebRequest y WebClient, pero dado que la descarga se inicia con un javascript, ahora sé la URL del archivo. Fyi, el javascript es una función doPostBack que cambia algunos valores y envía un formulario.

He intentado enfocarme en el diálogo Guardar como WebBrowser para automatizarlo desde allí sin mucho éxito. Sé que hay una manera de forzar que la descarga se guarde en lugar de pedir guardar o abrir agregando un encabezado a la solicitud http, pero no sé cómo especificar la ruta de archivo para descargar.

+0

¿Tiene una solución a su última problema, cómo descargar el archivo cuando se genera sobre la marcha y no se puede determinar que se trata de una descarga de archivo desde la url? –

Respuesta

5

Creo que debe evitar que el diálogo de descarga se muestre. Aquí podría ser una manera de hacerlo:

  • El código Javascript hace que el control WebBrowser para acceder a una URL específica (lo que provocará que aparezca el diálogo de descarga)

  • Para evitar el control WebBrowser desde de hecho, navegando a esta URL, adjunte un controlador de eventos al evento Navegación.

  • En su evento Navegación debería analizar si esta es la acción de Navegación real que desea detener (esta es la URL de descarga, tal vez buscar una extensión de archivo, debe haber un formato reconocible) . Use WebBrowserNavigatingEventArgs.Url para hacerlo.

  • Si esta es la URL correcta, detenga la navegación configurando la propiedad WebBrowserNavigatingEventArgs.Cancel.

  • Continuar la descarga a sí mismo con las clases HttpWebRequest o WebClient

un vistazo a esta página para obtener más información sobre el evento:
http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.navigating.aspx

+1

Ya he intentado obtener la URL usando un HttpDebugger para ver la solicitud y las respuestas http. La url es exactamente la misma, una es una solicitud GET, la otra es una solicitud POST. También intenté su sugerencia sin suerte. – Sharath

+0

Es posible que desee utilizar el control WebBrowser para llegar al final, justo antes de enviar el formulario y luego extraer el destino POST del formulario usando DOM (obtener una referencia al cuerpo del documento HTML y desde allí dirigirse a la forma). – Zyphrax

3

Una solución similar se encuentra disponible en http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/d338a2c8-96df-4cb0-b8be-c5fbdd7c9202/?prof=required

Esto funciona perfectamente si hay una URL directa que incluye la descarga del nombre de archivo.

Pero a veces algunas URL generan archivos dinámicamente. Entonces, la URL no tiene el nombre del archivo, pero después de solicitar esa URL, un sitio web crea el archivo dinámicamente y luego aparece el diálogo abrir/guardar.

por ejemplo, algún enlace generar archivo PDF sobre la marcha.

¿Cómo se maneja ese tipo de URL?

1

Tome un vistazo a Erika artículo Chinchio en http://www.codeproject.com/Tips/659004/Download-of-file-with-open-save-dialog-box

he utilizado con éxito para descargar pdf direcciones URL generadas dinámicamente.

+2

Si bien esto podría responder teóricamente a la pregunta, [sería preferible] (// meta.stackoverflow.com/q/8259) incluir aquí las partes esenciales de la respuesta y proporcionar el enlace de referencia. –

1

Suponiendo que el System.Windows.Forms.WebBrowswer se utilizó para acceder a una página protegida con un enlace protegido que desea descargar:

Este código recupera el vínculo real que se desea descargar usando la web navegador. Este código deberá cambiarse para su acción específica. La parte importante es este campo documentLinkUrl que se utilizará a continuación.

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); 

Ahora que la página protegida se ha navegado por el navegador web y el enlace de descarga se ha adquirido, este código de descarga el enlace.

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 

     } 
    } 
} 

El código anterior se basa en el método de GetGlobalCookies Erika Chinchio que se puede encontrar en el excelente artículo proporcionada por @Pedro Leonardo (disponible 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; 
} 
Cuestiones relacionadas