如何在 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 类型。我从这条评论中得到了解决方案 -
在工作中,我们登录到作为文件存储库的提供商网站。出现文件列表。每个文件名都是 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 类型。我从这条评论中得到了解决方案 -