Все данные не импортируются с сайта, чтобы преуспеть - PullRequest
0 голосов
/ 31 мая 2019

Я хочу импортировать данные ресторана, такие как название ресторана, номер телефона и веб-сайт, чтобы преуспеть, но, к сожалению, я получаю только одну страницу (первую страницу), однако мне нужны данные из любого диапазона, который я определяю, например, от страницы 1 до страницы 3 илиот страницы 2 до страницы 5 в отдельных листах для каждой страницы.Пример выходного файла прилагается, какой вывод я получаю в настоящее время.enter image description here

    Sub Webscraping()
        'Declaration
     Dim ie As InternetExplorer
     Dim ht As HTMLDocument
    'Initialization
     Set ie = New InternetExplorer
     ie.Visible = True

'Open a url
ie.navigate ("https://www.yellowpages.com/atlanta-ga/restaurants")

'Set ht = ie.document
'MsgBox ht.getElementsByClassName("ot_lrp_bname_free_center")

'Alternative Approach for wait

Do Until ie.readyState = READYSTATE_COMPLETE
    DoEvents
Loop

'Initialize the document

Set ht = ie.document

'Set elems = ht.getElementsByClassName("list-title")
Set elems = ht.getElementsByClassName("business-name")
'Set elems = ht.getElementsByClassName("website-lrp icon-link ot_lrp_website_text_free_center")

i = 1
For Each elem In elems
    Sheet1.Cells(i, 1).Value = elem.innerText
    i = i + 1

    'Debug.Print (elem.innerText)
Next

Set elems = ht.getElementsByClassName("phone primary")

i = 1
For Each elem In elems
    Sheet1.Cells(i, 2).Value = elem.innerText
    i = i + 1

   'Debug.Print (elem.innerText)
Next
Set elems = ht.getElementsByClassName("links")
i = 1
For Each elem In elems

    Set link = elem.ChildNodes.Item(0)
    Sheet1.Cells(i, 3).Value = link.href
    i = i + 1    
Next

'Set internetdata = ie.document
'Set div_result = internetdata.getElementById("ctl00_gvMain_ctl03_hlTitle")
'Set header_links = div_result.getElementsByTagName("a")
'For Each h In header_links
'Set link = h.ChildNodes.Item(0)
'Worksheets("Stocks").Cells(Range("L" & Rows.Count).End(xlUp).Row + 1, 12) = link.href
 End Sub

Это работа, которая была проделана, но изо всех сил пыталась получить требуемый выход

Ответы [ 2 ]

2 голосов
/ 31 мая 2019

Страницы объединяются в конец URL.Я бы использовал запросы на выдачу xhr в цикле по заданному диапазону страниц и выводил бы json, который содержит необходимую информацию (он находится в одном из тегов скрипта).Этот метод очень быстрый и более чем компенсирует использование регулярных выражений.Я также использую объекты, где это возможно.

Я использую jsonconverter.bas для обработки json и анализа необходимой информации (в json гораздо больше информации, включая обзоры).После загрузки .bas и добавления в модуль JsonConverter в вашем проекте вам нужно перейти в VBE> Инструменты> Ссылки> Добавить ссылку в Microsoft Scripting Runtime.

Вспомогательные функции используются для проверки того, должна ли страница записываться.уже существует или требует создания, а также для записи результатов json в массив и выгрузки массива за один переход к листу (повышение эффективности).Структура оставлена, поэтому легко получить извлеченную информацию, если требуется дополнительная информация, например, обзор.

Может потребоваться некоторая работа по обеспечению работ для страниц, которые не существуют.Я просто использовал код ответа в настоящее время, чтобы отфильтровать их.


ПРИМЕЧАНИЯ:

В качестве проверки работоспособности я бы использовал InternetExplorer для перехода на страницу1 и извлеките общее количество результатов.Я бы разделил это по результатам на страницу (в настоящее время 30), чтобы рассчитать общее количество страниц.Это даст мне значения lbound и ubound (min и max для возможных страниц).Затем переключитесь на xmlhttp для фактического получения.См. Дополнительную вспомогательную функцию в конце.


Код:

Option Explicit
Public Sub GetRestuarantInfo()
    Dim s As String, re As Object, p As String, page As Long, r As String, json As Object
    Const START_PAGE As Long = 2
    Const END_PAGE As Long = 4
    Const RESULTS_PER_PAGE As Long = 30

    p = "\[{""@context"".*?\]"
    Set re = CreateObject("VBScript.RegExp")

    Application.ScreenUpdating = False

    With CreateObject("MSXML2.XMLHTTP")

        For page = START_PAGE To END_PAGE
            .Open "GET", "https://www.yellowpages.com/atlanta-ga/restaurants?page=" & page, False
            .send
            If .Status = 200 Then
                s = .responseText
                r = GetValue(re, s, p)
                If r <> "Not Found" Then
                    Set json = JsonConverter.ParseJson(r)
                    WriteOutResults page, RESULTS_PER_PAGE, json
                End If
            End If
        Next
    End With
    Application.ScreenUpdating = True
End Sub
Public Sub WriteOutResults(ByVal page As Long, ByVal RESULTS_PER_PAGE As Long, ByVal json As Object)
    Dim sheetName As String, results(), r As Long, headers(), ws As Worksheet
    ReDim results(1 To RESULTS_PER_PAGE, 1 To 3)

    sheetName = "page" & page
    headers = Array("Name", "Website", "Tel")
    If Not WorksheetExists(sheetName) Then
        Set ws = ThisWorkbook.Worksheets.Add
        ws.Name = sheetName
    Else
        ThisWorkbook.Worksheets(sheetName).Cells.ClearContents
    End If
    With ws
        Dim review As Object
        For Each review In json  'collection of dictionaries
            r = r + 1
            results(r, 1) = review("name")
            results(r, 2) = review("url")
            results(r, 3) = review("telephone")
        Next
        .Cells(1, 1).Resize(1, UBound(headers) + 1) = headers
        .Cells(2, 1).Resize(UBound(results, 1), UBound(results, 2)) = results
    End With
End Sub

Public Function GetValue(ByVal re As Object, inputString As String, ByVal pattern As String) As String
'https://regex101.com/r/M9oRON/1
    With re
        .Global = True
        .MultiLine = True
        .IgnoreCase = False
        .pattern = pattern
        If .Test(inputString) Then
            GetValue = .Execute(inputString)(0)
        Else
            GetValue = "Not found"
        End If
    End With
End Function

Public Function WorksheetExists(ByVal sName As String) As Boolean  '@Rory https://stackoverflow.com/a/28473714/6241235
    WorksheetExists = Evaluate("ISREF('" & sName & "'!A1)")
End Function

Вспомогательная функция для возврата количества страниц

'VBE > Tools > References: Microsoft Internet Controls
Public Function GetNumberOfPages(ByVal RESULTS_PER_PAGE As Long) As Variant
    Dim ie As Object, totalResults As Long
    On Error GoTo errhand
    Set ie = CreateObject("InternetExplorer.Application")
    With ie
        .Visible = False
        .Navigate2 "https://www.yellowpages.com/atlanta-ga/restaurants?page=1"

        While .Busy Or .readyState < 4: DoEvents: Wend

        With .document
            totalResults = Replace$(Replace$(.querySelector(".pagination  p").innerText, "We found", vbNullString), "results", vbNullString)
            GetNumberOfPages = totalResults / RESULTS_PER_PAGE
            ie.Quit
            Exit Function
        End With
    End With
errhand:
    If Err.Number <> 0 Then
        GetNumberOfPages = CVErr(xlErrNA)
    End If
End Function

Regex объяснение:

Попробуйте здесь .

enter image description here

0 голосов
/ 31 мая 2019

Единственный способ сделать это с помощью VBA - проверить наличие кнопки «Далее» и щелкнуть ее, если она есть:

enter image description here

Это HTML-код:

<a class="next ajax-page" href="/atlanta-ga/restaurants?page=2" data-page="2" data-analytics="{&quot;click_id&quot;:132}" data-remote="true" data-impressed="1">Next</a>

Это не «научная фантастика», которую нужно делать с VBA, однако существуют коммерческие решения RPA, которые предоставляют функциональные возможности «из коробки»именно для этой задачи - UiPath, AutomationAnywhere, BluePrism.«Красивый суп» Питона тоже неплохо бы справился.

...