Как лучше всего обработать HTML-пакет Agiligy для HTML? - PullRequest
0 голосов
/ 08 апреля 2019

Я не могу получить HTML от нескольких сайтов, но могу от многих других.Вот 2 сайта, с которыми у меня проблемы:

https://www.rei.com

https://www.homedepot.com

Я создаю приложение, которое будетполучить информацию метатега из URL, который вводит пользователь.Получив код HTML, я обрабатываю его с помощью пакета Agility HTML, и он работает отлично.Проблема заключается в получении HTML-кода с различных веб-сайтов.

Я пробовал разные способы получить HTML-код (HtmlWeb, HttpWebRequest и другие), все с помощью установки user-agent (тот же тег агента, что и в Chrome).), заголовки, куки и автоадресация, gzip-ы и, похоже, каждая комбинация.Все проверено, выглядя как Fiddler, но я не могу понять, почему я не могу получить HTML с некоторых сайтов, они просто перестают работать, когда я могу просто найти тот же URL в своем браузере.Заголовки, которые я отправляю, выглядят так же, как Fiddler.Кто-нибудь знает, что заставляет URL не возвращать HTML / данные?Или у кого-нибудь есть пакет или платформа NuGet, которые обрабатывают все нюансы получения HTML-страницы / документа, независимо от того, является ли веб-сайт SSL, gzip, требуются файлы cookie, перенаправления и т. Д. *

Зайдя в этот проект, яЯ думал, что самой сложной частью будет обработка HTML, а не получение, поэтому любая помощь будет оценена.

ОБНОВЛЕНИЕ 1:

Я пытался, но просто не могузаставить его работать ... Я, должно быть, упускаю что-то простое ... вот обновленный пример с некоторыми из предложенных изменений.

https://dotnetfiddle.net/tQyav7

Мне пришлось закомментировать ServerCertificateValidationCallback на dotnetfiddle, потому что он выдавал ошибку там, но ее нет в моем окне разработчика.Я также должен был установить тайм-аут всего на 5 секунд ... У меня он равен 20 на моем устройстве dev.Любая помощь будет оценена.

1 Ответ

0 голосов
/ 09 апреля 2019

Это ваш класс helper , реорганизованный для поддержки большинства веб-ответов, которые может обрабатывать HttpWebResponse.

Примечание: никогда не выполняйте настройки такого рода, если у вас нет Option Explicit и Option Strict, настроенных на True: вы никогда не сделаете это правильно , Автоматический вывод здесь не ваш друг (ну, на самом деле, никогда; вам действительно нужно знать, с какими объектами вы имеете дело).

Что было изменено и что важно:

  • Обработка Tls: расширенная поддержка Tls 1.1, Tls 1.2 и максимальная версия протокола, которую может обрабатывать текущая структура:

    System.Enum.GetValues(GetType(SecurityProtocolType)).OfType(Of SecurityProtocolType)().Max()
    
  • WebRequest.ServicePoint.Expect100Continue = False: вы никогда не хотите такого ответа, если вы не готовы подчиниться. Но это никогда не нужно.

  • [AutomaticDecompression][1] требуется, если вы не хотите обрабатывать потоки GZip или Deflate вручную . Это почти никогда не требуется (только если вы хотите проанализировать исходный поток перед его распаковкой).

  • CookieContainer перестраивается каждый раз. Это не было изменено, но вы можете хранить статический объект и повторно использовать файлы cookie при каждом запросе: некоторые сайты могут устанавливать файлы cookie при выполнении рукопожатия Tls и перенаправлять на страницу входа. WebRequest может использоваться для параметров проверки подлинности POST (кроме капч), но вам необходимо сохранить Cookies, в противном случае любой дальнейший запрос не будет аутентифицирован.

  • Метод Response Stream ReadToEnd() также оставлен как есть, но вы должны изменить его для чтения буфера. Это позволит, например, показать ход загрузки, а также отменить операцию, если это необходимо.

  • Важно : UserAgent не может быть установлен на последнюю версию любого существующего браузера. Некоторые веб-сайты, обнаружив, что пользовательский агент поддерживает протокол HSTS , активируют его и ждут взаимодействия. WebRequest ничего не знает о HSTS и истечет время ожидания. Я установил UserAgent на Internet Explorer 11. Он отлично работает на всех сайтах.

  • Http Redirection настроен на автоматический, но иногда необходимо выполнить его вручную. Это может улучшить надежность этой процедуры. Вы можете, например, запретить перенаправления за пределы области назначения. Или изменение протокола HTTP, которое вы не поддерживаете.

Предложение: этот класс получит выгоду от async версии методов HttpWebRequest: вы сможете выдавать несколько одновременных запросов вместо того, чтобы ожидать синхронного завершения каждого из них.
Требуется всего несколько модификаций, чтобы превратить этот класс в асинхронную версию.

Этот класс теперь должен поддерживать большинство HTML-страниц, которые не используют сценарии для асинхронной сборки содержимого.
Как уже описано в комментариях, Lazy HttpClient может обрабатывать некоторые (не все) из этих страниц, но для этого требуется совершенно другая настройка.

Imports System
Imports System.IO
Imports System.Net
Imports System.Net.Security
Imports System.Security.Cryptography.X509Certificates
Imports System.Text

Public Class WebRequestHelper
    Private m_ResponseUri As Uri
    Private m_StatusCode As HttpStatusCode
    Private m_StatusDescription As String
    Private m_ContentSize As Long
    Private m_WebException As WebExceptionStatus
    Public Property SiteCookies As CookieContainer
    Public Property UserAgent As String = "Mozilla / 5.0(Windows NT 6.1; WOW32; Trident / 7.0; rv: 11.0) like Gecko"
    Public Property Timeout As Integer = 30000
    Public ReadOnly Property ContentSize As Long
        Get
            Return m_ContentSize
        End Get
    End Property

    Public ReadOnly Property ResponseUri As Uri
        Get
            Return m_ResponseUri
        End Get
    End Property

    Public ReadOnly Property StatusCode As Integer
        Get
            Return m_StatusCode
        End Get
    End Property

    Public ReadOnly Property StatusDescription As String
        Get
            Return m_StatusDescription
        End Get
    End Property

    Public ReadOnly Property WebException As Integer
        Get
            Return m_WebException
        End Get
    End Property


    Sub New()
        SiteCookies = New CookieContainer()
    End Sub

    Public Function GetSiteResponse(ByVal siteUri As Uri) As String
        Dim response As String = String.Empty

        ServicePointManager.DefaultConnectionLimit = 50
        Dim maxFWValue As SecurityProtocolType = System.Enum.GetValues(GetType(SecurityProtocolType)).OfType(Of SecurityProtocolType)().Max()
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12 Or maxFWValue
        ServicePointManager.ServerCertificateValidationCallback = AddressOf TlsValidationCallback

        Dim Http As HttpWebRequest = WebRequest.CreateHttp(siteUri.ToString)
        With Http
            .Accept = "ext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
            .AllowAutoRedirect = True
            .AutomaticDecompression = DecompressionMethods.GZip Or DecompressionMethods.Deflate
            .CookieContainer = Me.SiteCookies
            .Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate")
            .Headers.Add(HttpRequestHeader.AcceptLanguage, "en-US,en;q=0.7")
            .Headers.Add(HttpRequestHeader.CacheControl, "no-cache")
            .KeepAlive = True
            .MaximumAutomaticRedirections = 50
            .ServicePoint.Expect100Continue = False
            .ServicePoint.MaxIdleTime = Me.Timeout
            .Timeout = Me.Timeout
            .UserAgent = Me.UserAgent
        End With

        Try
            Using webResponse As HttpWebResponse = DirectCast(Http.GetResponse, HttpWebResponse)
                Me.m_ResponseUri = webResponse.ResponseUri
                Me.m_StatusCode = webResponse.StatusCode
                Me.m_StatusDescription = webResponse.StatusDescription
                Dim contentLength As String = webResponse.Headers.Get("Content-Length")
                Me.m_ContentSize = If(String.IsNullOrEmpty(contentLength), 0, Convert.ToInt64(contentLength))

                Using responseStream As Stream = webResponse.GetResponseStream()
                    If webResponse.StatusCode = HttpStatusCode.OK Then
                        Dim reader As StreamReader = New StreamReader(responseStream, Encoding.Default)
                        Me.m_ContentSize = webResponse.ContentLength
                        response = reader.ReadToEnd()
                        Me.m_ContentSize = If(Me.m_ContentSize = -1, response.Length, Me.m_ContentSize)
                    End If
                End Using
            End Using
        Catch exW As WebException
            If exW.Response IsNot Nothing Then
                Me.m_StatusCode = CType(exW.Response, HttpWebResponse).StatusCode
            End If
            Me.m_StatusDescription = "WebException: " & exW.Message
            Me.m_WebException = exW.Status
        End Try
        Return response
    End Function

    Private Function TlsValidationCallback(sender As Object, CACert As X509Certificate, CAChain As X509Chain, SslPolicyErrors As SslPolicyErrors) As Boolean
        If SslPolicyErrors = SslPolicyErrors.None Then Return True
        Dim Certificate As New X509Certificate2(CACert)

        CAChain.Build(Certificate)
        For Each CACStatus As X509ChainStatus In CAChain.ChainStatus
            If (CACStatus.Status <> X509ChainStatusFlags.NoError) And
                (CACStatus.Status <> X509ChainStatusFlags.UntrustedRoot) Then
                Return False
            End If
        Next
        Return True
    End Function

End Class
...