【问题标题】:Download file after authenticated through WebBrowser通过WebBrowser认证后下载文件
【发布时间】:2021-07-04 14:32:30
【问题描述】:

背景

所以我正在创建一个 VB .NET 程序,它基本上会登录到一个网页,点击一堆按钮,这会导致网站生成一个可以下载的 Excel 报告。我已经成功完成了生成文件的所有步骤,所以现在我正在尝试创建一种方法,该方法将在后台下载文件而不出现“另存为”对话框。

详情

我已经设法通过 Webbrowser 控件的 Navigating 事件捕获下载:

Public Sub a(sender As Object, e As WebBrowserNavigatingEventArgs) Handles WebBrowser1.Navigating
    'intercept the excel download. Retrieve the url but cancel dialog
    If e.Url.AbsoluteUri.Contains("fmsdownload") Then
        Label3.Text = e.Url.AbsoluteUri
        e.Cancel = True
        'e.Url.AbsoluteUri = the temporarily generated file URL to download from
        'INSERT DOWNLOAD METHOD HERE
    End If
End Sub

我确认e.Url.AbsoluteUri 确实是正确的路径。如果我将此 URL 复制/粘贴到 Chrome 中,它会下载。

问题

所以最终我只是想在生成下载链接后找到一种下载文件的方法。请查看下面的部分,了解我所尝试的方法,因为我相信我已经接近成功了。

我尝试过的(发帖前请阅读)

  • 方法一:My.Computer.Network.DownloadFile(URL,SAVEPATH)。这导致服务器回退The repote server returned an error: (403) Forbidden。这让我明白身份验证没有通过,这是有道理的。

  • 方法 2:我阅读了一篇 stackoverflow 帖子,尝试使用 URLMON 来启动下载 (http://www.pinvoke.net/default.aspx/urlmon/URLDownloadToFile%20.html)。我认为这会有一些承诺,但会导致错误Unable to find an entry point named URLDownloadToFile in DLL 'URLMON.dll' 这是我用于此方法的代码,因为它可能是我缺少的一些简单的东西:

    Private Declare Sub URLDownloadToFile _
    Lib "URLMON.dll" (
    ByVal lpCaller As Long,
    ByVal szUrl As String,
    ByVal szFilename As String,
    ByVal dwReserved As Long,
    ByVal lpBindStatusCallback As Long)
    
    Public Sub a(sender As Object, e As WebBrowserNavigatingEventArgs) Handles WebBrowser1.Navigating
     'intercept the excel download. Retrieve the url but cancel dialog
     If e.Url.AbsoluteUri.Contains("fmsdownload") Then
         Label3.Text = e.Url.AbsoluteUri
         e.Cancel = True
    
         Try
             Kill(My.Computer.FileSystem.SpecialDirectories.MyDocuments & "\download.xls")
         Catch
         End Try
    
         URLDownloadToFile(0, e.Url.AbsoluteUri, My.Computer.FileSystem.SpecialDirectories.MyDocuments & "\download.xls", 0, 0)
    
     End If
    

    结束子

  • 方法 3:经过一些研究,似乎身份验证存储为 cookie,因此我尝试检索 cookie,然后将它们提供给 WebClient,因为 WebClient 支持下载文件。这是我捕获 cookie 的地方:

    Dim cookie_collection() As String
    Public Sub webbrowser1_documentcompleted(sender As Object, e As 
    WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
    
     If WebBrowser1.Document.Cookie Is Nothing Then
     Else
         Dim cookies As String() = WebBrowser1.Document.Cookie.Split({";"c}, StringSplitOptions.None)
    
         For Each cookie As String In cookies
             Dim name As String = cookie.Substring(0, cookie.IndexOf("="c)).TrimStart(" "c)
             Dim value As String = cookie.Substring(cookie.IndexOf("="c) + 1)
             If cookie_collection Is Nothing Then
                 ReDim cookie_collection(0)
             Else
                 ReDim Preserve cookie_collection(cookie_collection.Length)
             End If
             cookie_collection(cookie_collection.Length - 1) = cookie
             ' MsgBox(cookie)
         Next cookie
     End If
    
    
     End Sub
    

我验证在身份验证过程中捕获了两个cookie:

所以我尝试在下载之前将 cookie 重新应用到我的 WebClient:

   Public Sub a(sender As Object, e As WebBrowserNavigatingEventArgs) Handles WebBrowser1.Navigating
    'intercept the excel download. Retrieve the url but cancel dialog
    If e.Url.AbsoluteUri.Contains("fmsdownload") Then
        Label3.Text = e.Url.AbsoluteUri
        e.Cancel = True

        Dim client As New System.Net.WebClient
        For Each cookie As String In cookie_collection
            client.Headers.Add(Net.HttpRequestHeader.Cookie, cookie)
        Next

        client.DownloadFile(e.Url.AbsoluteUri, My.Computer.FileSystem.SpecialDirectories.MyDocuments & "\download.xls")

    End If
End Sub

不幸的是,这导致了与The repote server returned an error: (403) Forbidden 之前相同的错误,这让我意识到身份验证仍未通过。

我知道这是一篇大文章,但我觉得方法 2 或方法 3 应该可行,所以我可能遗漏了一些小东西(我希望如此)。

【问题讨论】:

    标签: vb.net download webbrowser-control webclient


    【解决方案1】:

    在您使用WebClient 检索文件的最后一段代码中,您当前将cookie 添加到请求中,如下所示:

    For Each cookie As String In cookie_collection
        client.Headers.Add(Net.HttpRequestHeader.Cookie, cookie)
    Next
    

    但是,HTTP 中只有一个参数包含同时包含所有 cookie,因此您通过为每个 cookie 推送一个新标头来覆盖以前的 cookie。因此,您不需要使用 String.Split 来提取 cookie,而是按原样使用分号传递参数,因为 HTTP 应该可以解决所有问题。希望这能解决您的问题!

    编辑:这是我认为可能会解决的问题: 像这样检索DocumentCompleted 事件中的cookie(代码的第三位):

    Dim cookie_collection As String
    Public Sub webbrowser1_documentcompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
    
        If WebBrowser1.Document.Cookie IsNot Nothing Then
           Dim cookies As String = WebBrowser1.Document.Cookie
           If cookie_collection = "" Then
               cookie_collection = cookies
           Else
               cookie_collection &= ";" & cookies
           End If
        End If
    End Sub
    

    然后只需将cookie_collection 字段传递给标题即可:

    ...
    Dim client As New System.Net.WebClient
    client.Headers.Add(Net.HttpRequestHeader.Cookie, cookie_collection)
    client.DownloadFile(e.Url.AbsoluteUri, My.Computer.FileSystem.SpecialDirectories.MyDocuments & "\download.xls")
    ...
    

    【讨论】:

    • 感谢您的回复!我试图替换我的初始代码,但仍然出现 Forbidden 错误。我还缺少什么吗?:If WebBrowser1.Document.Cookie Is Nothing Then Else Dim cookie As String = WebBrowser1.Document.Cookie If cookie_collection Is Nothing Then ReDim cookie_collection(0) Else ReDim Preserve cookie_collection(cookie_collection.Length) End If cookie_collection(cookie_collection.Length - 1) = cookie End If
    • 我实际上是指最后一段代码而不是第三段,抱歉!刚刚编辑过。
    • 没问题,但不幸的是没有骰子。我仍然收到禁止错误。这是我生成的标题:Cookie: csrf_cookie=ade98ec8-1558-4517-b5ea-3d1a4507bf5f; JSESSIONID=iyay4Wex2KcqxCr-wBjn19LF1FvbxvumPbbpdV7v-kZuOSKFxoCi!147640388!-765605226;csrf_cookie=10150dc2-5b65-4b62-a27a-d934baedb187; JSESSIONID=iyay4Wex2KcqxCr-wBjn19LF1FvbxvumPbbpdV7v-kZuOSKFxoCi!147640388!-765605226 你认为csrf_cookieJSESSIONID 被设置两次是个问题吗?
    • 仅供参考,我尝试对其进行操作,因此只加载了第一组 cookie 以及第二组 cookie,但仍然是一个禁止错误..
    • 那很不幸...但是通过WebBrowser 下载文件可以正常工作,我猜?您是否尝试过通过WebBrowser 捕获手动下载过程中设置的 cookie 并查看它们是否不同?此外,唯一看似不变的参数是JSESSIONID,因此可以尝试仅将此参数作为唯一的 cookie 传递。如果仍然无效,则问题可能与 cookie 无关,而是与其他身份验证失败有关,例如 HTTP 身份验证(尽管我认为这不太可能)
    猜你喜欢
    • 2013-03-03
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多