Как разделить файлы cookie между элементом управления WebBrowser и CookieAwareWebClient? - PullRequest
0 голосов
/ 15 марта 2019

На работе мы заходим на сайт провайдера, который служит хранилищем файлов.Появится список файлов.Каждое имя файла является ссылкой.Нажмите на ссылку и загрузите файл.Это очень легкий веб-сайт.

Я пытаюсь войти в систему и загрузить файлы без утомительной задачи щелкать по каждому из них (флажок «выбрать все» отсутствует).Для начала я использую элемент управления 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

Вот одна из многих версий CookieAwareWebClient, найденных здесь на SO.

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 после успешного входа в систему, выглядят так (каждый раз по разным токенам).

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

Я проверил, что это те же самые куки, которые входят в 'webRequest.CookieContainer'.Кроме того, в элементе управления WebBrowser после входа в систему можно щелкнуть ссылку на файл, чтобы загрузить его.

Кто-нибудь видит что-то явно неправильное в коде?

Продолжая гуглить во время написания вопроса, я только что наткнулся на Примечания для наследников в документации MS для WebClient - «Производные классы должны вызывать реализацию базового класса WebClient, чтобы гарантировать, что производный класс работает должным образом».

Это звучит как то, что вы бы сделали в конструкторе?Или об этом позаботились в утверждении MyBase.GetWebRequest(address)?

1 Ответ

0 голосов
/ 18 марта 2019

После долгого взлома и гугла, я собираюсь заключить, что это миф, что вы можете сделать WebClient "осведомленным о cookie".Я никогда не мог заставить это работать, и почти все темы, которые я прочитал, закончились без решения.В любом случае, WebClient явно устарел.

Напомним, что миссия состояла в том, чтобы автоматизировать вход в систему и загрузку файлов с веб-сайта с низким уровнем безопасности, который использует проверку подлинности с помощью форм.Элемент управления WebBrowser работал бы нормально, за исключением того, что он использует IE, а IE отказывается загружать PDF-файлы без вывода сообщений.Он настаивает на подсказке, открывать, сохранять или удалять.

Я начал играть с HTTPWebRequest, HTTPRequest, WebRequest, HTTPClient и кучей вариантов, и ни к чему не привел.Затем мне пришло в голову искать элемент управления WebBrowser на основе Chrome, и я наткнулся на Selenium.Для меня это оказалось решением.

Основное назначение Selenium - тестирование программного обеспечения, но оно также позволяет вам манипулировать веб-страницами.Вы можете легко установить его в Visual Studio через NuGet.Вам также необходимо установить драйвер для конкретного браузера.Есть драйверы для всех основных браузеров, но использование драйвера 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.Это просто не работало.Оказалось, что у меня был неправильный тип пантомимы.Я получил решение для этого из этого комментария - Настройка профиля Firefox для автоматической загрузки файлов с использованием Selenium и Java

...