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

时间:2019-03-15 19:38:26

标签: .net vb.net web-scraping webclient

在工作中,我们登录到提供商的网站,该网站充当文件存储库。出现文件列表。每个文件名都是一个链接。单击链接,然后下载文件。这是一个非常轻巧的网站。

我试图登录并下载文件,而没有单击每个文件的繁琐任务(没有“全选”复选框)。我正在使用带有“开始”按钮的表单上的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"

我已经验证了那些与“ webRequest.CookieContainer”中使用的cookie是相同的。同样,在WebBrowser控件中,登录后,您可以单击文件的链接进行下载。

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

在写问题时仍在谷歌搜索,我只是在WebClient的MS文档中遇到Notes to Inheritors -“派生类应调用WebClient的基类实现以确保派生类按预期工作。”

这听起来像您将在构造函数中执行的操作?还是在语句MyBase.GetWebRequest(address)中解决了这个问题?

1 个答案:

答案 0 :(得分:0)

在遭受了许多黑客和Google攻击之后,我将得出一个结论,那就是可以使WebClient“ Cookie感知”是一个神话。我永远无法使它工作,而我所读到的几乎所有线程都得出结论,没有解决方案。无论如何,显然不推荐使用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部分遇到了问题。只是没有用。原来我的哑剧类型错误。我从此评论中得到了解决方案-Set Firefox profile to download files automatically using Selenium and Java