如何在 WebBrowser 控件和 CookieAwareWebClient 之间共享 cookie?

How to share cookies between WebBrowser control and CookieAwareWebClient?

在工作中,我们登录到作为文件存储库的提供商网站。出现文件列表。每个文件名都是 link。点击link,下载文件。这是一个非常轻量级的网站。

我正在尝试登录并下载文件,而无需单击每个文件的繁琐任务(没有 "select all" 复选框)。我在一个带有开始按钮的窗体上使用 WebBrowser 控件。这是代码。请跳到星号所在的行。

Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click
    Try
        PageLoaded = False
        browser.Navigate("https://[the website]/Account/Login.htm", False)
        While Not PageLoaded
            Application.DoEvents()
        End While
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
    Try
        browser.Document.GetElementById("username").InnerText = [username]
        browser.Document.GetElementById("password").InnerText = [password]
        PageLoaded = False
        browser.Document.Forms("mainform").InvokeMember("submit")
        While Not PageLoaded
            Application.DoEvents()
        End While
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try

    ' ************************************
    Dim mycookies As String
    mycookies = browser.Document.Cookie
    ' DEBUG: verified cookies are indeed present

    Try
        Dim cookieJar As New CookieContainer
        Dim cookies As String() = browser.Document.Cookie.Split({"; "}, StringSplitOptions.RemoveEmptyEntries)
        Dim cookievaluepairs() = cookies(0).Split("=")
        Dim cky As New Cookie(cookievaluepairs(0), cookievaluepairs(1))
        cky.Domain = browser.Document.Domain
        cookieJar.Add(cky)
        Dim cookievaluepairs1() = cookies(1).Split("=")
        Dim cky1 As New Cookie(cookievaluepairs(0), cookievaluepairs(1))
        cky1.Domain = browser.Document.Domain
        cookieJar.Add(cky1)
        ' DEBUG: verified cookieJar contains expected cookies

        Dim wwwclient As New CookieAwareWebClient(cookieJar)
        ' DEBUG: please see class code below

        Dim x As Integer
        Dim dlurl As String = ""
        Dim inputs As HtmlElementCollection = browser.Document.Links
        For Each elm As HtmlElement In inputs
            If Microsoft.VisualBasic.Left(elm.OuterHtml, 10) = "<A href=""/" Then
                dlurl = elm.GetAttribute("href")
                ' DEBUG: crappily named dlurl indeed has correct URI

                wwwclient.DownloadFile(dlurl, "D:\Desktop\file" & x)
                ' DEBUG: overriden function GetWebRequest fires
                '        please see class code below

            End If
        Next
    Catch ex As Exception
        MsgBox(ex.Message)
        ' DEBUG: always lands here with 401 error

    End Try
End Sub

这是在 SO 上找到的众多 CookieAwareWebClient 版本之一。

Public Class CookieAwareWebClient
    Inherits WebClient

    Private m_container As CookieContainer = New CookieContainer()

    Public Sub New(cc As CookieContainer)
        m_container = cc
        ' DEBUG: verified m_container now has cookieJar passed as cc
    End Sub


    Protected Overrides Function GetWebRequest(ByVal address As Uri) As WebRequest
        Dim request As WebRequest = MyBase.GetWebRequest(address)
        Dim webRequest As HttpWebRequest = TryCast(request, HttpWebRequest)

        If webRequest IsNot Nothing Then
            webRequest.CookieContainer = m_container
        End If

        Return webRequest
        ' DEBUG: verified webRequest.CookieContainer is correct
    End Function
End Class

我单步执行代码一直到 wwwclient.DownloadFile 语句,然后执行 GetWebRequest 函数中的代码,暂停后,我得到 401 Not Authorized。我发现的 CookieAwareWebClient 的五六个变体都发生过这种情况。

代码成功登录后,我从 WebBrowser 控件中检索到的两个 cookie 如下所示(每次 obv 都有不同的标记)。

"samlssologgedout=SSO%20Logged%20Out" "token=A4AA416E-46C8-11e9-92CD-005056A005E4"

我已确认这些 cookie 与进入 'webRequest.CookieContainer' 的 cookie 相同。同样,在WebBrowser控件中,登录后,可以点击文件的link进行下载。

有人看到代码中有什么明显的错误吗?

写问题时仍在谷歌搜索,我刚刚在 WebClient 的 MS 文档中遇到 Notes to Inheritors -- "Derived classes should call the base class implementation of WebClient to ensure the derived class works as expected."

这听起来像是您会在构造函数中做的事情?或者这在语句 MyBase.GetWebRequest(address)?

中得到了处理

经过多次破解和 google,我将得出结论,您可以制作 WebClient 是一个神话 "cookie aware." 我永远无法让它工作,而且我读过的几乎所有关于它的主题以无解告终。无论如何,WebClient 显然已被弃用。

总而言之,任务是从使用表单身份验证的低安全性网站自动登录和下载文件。 WebBrowser 控件本来可以正常工作,只是它使用 IE,而 IE 拒绝静默下载 PDF 文件。非要提示打开,保存,还是丢弃

我开始尝试使用 HTTPWebRequest、HTTPRequest、WebRequest、HTTPClient 和许多变体,但一无所获。然后我想到寻找一个基于 Chrome 的 WebBrowser 控件,我偶然发现了 Selenium。事实证明这是我的解决方案。

Selenium 的主要用途似乎是测试软件,但它也可以让您操作网页。您可以通过 NuGet 在 Visual Studio 内轻松安装它。您还需要安装特定于浏览器的驱动程序。每个主要浏览器都有驱动程序,但使用 IE 驱动程序将毫无意义,因为我仍然会遇到在每个文件上都被提示的问题。我反而下载了 Chrome 和 Firefox 驱动程序。他们允许这里的用户在两者之间进行选择,大约是50/50。

代码最终如此简单。

Dim Options = New FirefoxOptions
Options.SetPreference("browser.download.folderList", 2)
'Options.SetPreference("browser.download.dir", "C:\Windows\temp")
Options.SetPreference("browser.download.useDownloadDir", True)
Options.SetPreference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream")
Options.SetPreference("pdfjs.disabled", True)
Dim driverService = FirefoxDriverService.CreateDefaultService()
driverService.HideCommandPromptWindow = True
Dim browser = New FirefoxDriver(driverService, Options)
browser.Url = "https://[the website]"
browser.Navigate()
Dim elm = browser.FindElementById("username")
elm.SendKeys([the username])
elm = browser.FindElementById("password")
elm.SendKeys([the password])
elm = browser.FindElementById("loginSubmit")
elm.Click()
While InStr(browser.Url, "token") = 0
    Application.DoEvents()
End While
Dim links As IList(Of IWebElement) = browser.FindElementsByPartialLinkText(".")
For Each link As IWebElement In links
    link.Click()
Next

我 运行 遇到了 neverAsk.saveToDisk 部分的问题。它只是不起作用。原来我选错了 mime 类型。我从这条评论中得到了解决方案 -