2009-07-17 54 views
5

我一直在使用System.Windows.Forms.WebBrowser编写C#编写的WebCrawler。我正试图从网站上下载文件并将其保存在本地计算机上。更重要的是,我希望这是完全自动化的。点击一个调用JavaScript函数的按钮即可启动文件下载,该函数触发下载并显示“您要打开还是保存此文件?”对话框。我绝对不想手动点击“另存为”,然后输入文件名。使用WebBrowser无url的自动化文档下载

我知道HttpWebRequest和WebClient的下载功能,但由于下载是用javascript开始的,我现在知道该文件的URL。 Fyi,javascript是一个doPostBack函数,用于更改一些值并提交表单。

我试过把重点放在保存为WebBrowser的对话框上,以便在那里没有太大的成功自动化它。我知道有一种方法可以强制下载来保存,而不是通过向http请求添加头来保存或打开,但我不知道如何指定要下载的文件路径。

+0

你有一个解决方案,你最后问题,如何在动态生成文件时下载文件,并且您无法确定它是否是从网址下载的文件? – 2011-05-06 07:07:54

回答

5

我认为你应该防止下载对话框显示出来。这里可能是一个办法做到这一点:

  • 的JavaScript代码导致你的浏览器控件导航到一个特定的URL(什么会导致出现下载对话框)

  • 为了防止WebBrowser控件从实际导航到此Url,将事件处理程序附加到Navigating事件。

  • 在您的导航事件中,如果这是您想要停止的实际导航操作(这是一个下载URL,可能检查文件扩展名,必须有可识别的格式) 。使用WebBrowserNavigatingEventArgs.Url来执行此操作。

  • 如果这是正确的Url,请通过设置WebBrowserNavigatingEventArgs.Cancel属性来停止导航。

  • 自己继续下载用的HttpWebRequest或WebClient的类

看一看这个网页,了解事件的详细信息:
http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.navigating.aspx

+1

我已经尝试过让使用HttpDebugger看HTTP请求和响应的URL。 url完全一样,一个是GET请求,另一个是POST请求。 我也试过你的建议没有运气。 – Sharath 2009-07-17 20:40:53

+0

你可能想使用WebBrowser控件才能到尽头,表单将提交之前,然后提取使用DOM形式的POST目的地(获取到HTML文档正文的引用,并从那里用自己的方式表格)。 – Zyphrax 2009-07-18 10:52:41

1

假设System.Windows.Forms.WebBrowswer使用与您想要下载受保护的链接访问受保护的页面:

此代码检索实际的链接你想利用网络来下载浏览器。 此代码将需要为您的特定操作进行更改。重要的部分是这个字段documentLinkUrl,将在下面使用。

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

现在,受保护的页面已经被Web浏览器导航到和下载链接已被收购,此代码下载链接。

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 

     } 
    } 
} 

上面的代码依赖于从埃里卡Chinchio的GetGlobalCookies方法可以通过@Pedro莱昂纳多(可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; 
}