VBA - проблемы соскребания HTML

Я пытаюсь собрать данные аукциона с веб-сайта https://www.rbauction.com/heavy-equipment-auctions. Моя текущая попытка состояла в том, чтобы использовать приведенный ниже код, чтобы перетащить HTML-код веб-сайта в VBA, а затем проанализировать его и сохранить только те элементы, которые я хотел (название аукциона, количество дней, количество элементов).

Sub RBA_Auction_Scrape()

    Dim S_Sheet As Worksheet
    Dim Look_String As String
    Dim Web_HTML As String
    Dim HTTP_OBJ As New MSXML2.XMLHTTP60

    On Error GoTo ERR_LABEL:
    Set S_Sheet = ActiveWorkbook.ActiveSheet
    Web_HTML = ""
    HTTP_OBJ.Open "GET", "https://www.rbauction.com/heavy-equipment auctions", False
    HTTP_OBJ.Send
    On Error Resume Next
    Select Case HTTP_OBJ.Status
        Case 0: Web_HTML = HTTP_OBJ.responseText
        Case 200: Web_HTML = HTTP_OBJ.responseText
        Case Else: GoTo ERR_LABEL
    End Select

    Debug.Print Web_HTML

End Sub

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

1 ответ

Решение

Исходный HTML-код веб-страницы по предоставленной https://www.rbauction.com/heavy-equipment-auctions не содержит необходимых данных, он использует AJAX. На веб-сайте https://www.rbauction.com/ доступен API. Ответ возвращается в формате JSON. Перейдите на страницу, например, в Chrome, затем откройте окно "Инструменты разработчика" (F12), вкладку "Сеть", перезагрузите (F5) страницу и изучите зарегистрированные XHR. Наиболее релевантными данными являются строки JSON, возвращаемые URL-адресом https://www.rbauction.com/rba-api/calendar/v1?e1=true:

XHR-previev

XHR-заголовки

Вы можете использовать приведенный ниже код VBA для получения информации, как описано выше. Импортируйте модуль JSON.bas в проект VBA для обработки JSON.

Option Explicit

Sub Test_www_rbauction_com()

    Const Transposed = False ' Output option

    Dim sResponse As String
    Dim vJSON
    Dim sState As String
    Dim i As Long
    Dim aRows()
    Dim aHeader()

    ' Retrieve JSON data
    XmlHttpRequest "GET", "https://www.rbauction.com/rba-api/calendar/v1?e1=true", "", "", "", sResponse
    ' Parse JSON response
    JSON.Parse sResponse, vJSON, sState
    If sState <> "Object" Then
        MsgBox "Invalid JSON response"
        Exit Sub
    End If
    ' Pick core data
    vJSON = vJSON("auctions")
    ' Extract selected properties for each item
    For i = 0 To UBound(vJSON)
        Set vJSON(i) = ExtractKeys(vJSON(i), Array("eventId", "name", "date", "itemCount"))
        DoEvents
    Next
    ' Convert JSON structure to 2-d arrays for output
    JSON.ToArray vJSON, aRows, aHeader
    ' Output
    With ThisWorkbook.Sheets(1)
        .Cells.Delete
        If Transposed Then
            Output2DArray .Cells(1, 1), WorksheetFunction.Transpose(aHeader)
            Output2DArray .Cells(1, 2), WorksheetFunction.Transpose(aRows)
        Else
            OutputArray .Cells(1, 1), aHeader
            Output2DArray .Cells(2, 1), aRows
        End If
        .Columns.AutoFit
    End With
    MsgBox "Completed"

End Sub

Sub XmlHttpRequest(sMethod As String, sUrl As String, arrSetHeaders, sFormData, sRespHeaders As String, sContent As String)

    Dim arrHeader

    'With CreateObject("Msxml2.ServerXMLHTTP")
    '    .SetOption 2, 13056 ' SXH_SERVER_CERT_IGNORE_ALL_SERVER_ERRORS
    With CreateObject("MSXML2.XMLHTTP")
        .Open sMethod, sUrl, False
        If IsArray(arrSetHeaders) Then
            For Each arrHeader In arrSetHeaders
                .SetRequestHeader arrHeader(0), arrHeader(1)
            Next
        End If
        .send sFormData
        sRespHeaders = .GetAllResponseHeaders
        sContent = .responseText
    End With

End Sub

Function ExtractKeys(oSource, aKeys, Optional oDest = Nothing) As Object

    Dim vKey

    If oDest Is Nothing Then Set oDest = CreateObject("Scripting.Dictionary")
    For Each vKey In aKeys
        If oSource.Exists(vKey) Then
            If IsObject(oSource(vKey)) Then
                Set oDest(vKey) = oSource(vKey)
            Else
                oDest(vKey) = oSource(vKey)
            End If
        End If
    Next
    Set ExtractKeys = oDest

End Function

Sub OutputArray(oDstRng As Range, aCells As Variant)

    With oDstRng
        .Parent.Select
        With .Resize(1, UBound(aCells) - LBound(aCells) + 1)
            .NumberFormat = "@"
            .Value = aCells
        End With
    End With

End Sub

Sub Output2DArray(oDstRng As Range, aCells As Variant)

    With oDstRng
        .Parent.Select
        With .Resize( _
                UBound(aCells, 1) - LBound(aCells, 1) + 1, _
                UBound(aCells, 2) - LBound(aCells, 2) + 1)
            .NumberFormat = "@"
            .Value = aCells
        End With
    End With

End Sub

Вывод для меня выглядит следующим образом:

выход

Кстати, тот же подход применяется в следующих ответах: 1, 2, 3, 4, 5, 6 и 7.

Другие вопросы по тегам