Могу ли я переписать сценарий Excel VBA для других сайтов? - PullRequest
0 голосов
/ 28 октября 2018

Итак, в моем предыдущем посте, Здесь , все, кто принимал участие, оказали такую ​​большую помощь, но, к сожалению, я многому из этого не научился. Можно ли повторно использовать один из этих сценариев, чтобы очистить эту страницу и вывести подтвержденные / прогнозируемые составы в Excel? Посмотрев html, я вижу, что они размещены в классе div "lineups is-compact", а затем разделены в классе div "lineup is-nba".

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

Вот другие сайты, предоставляющие ту же информацию, с которой их легче получить.

RotoGrinders BB Monster

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

Option Explicit 
Public Sub GetInfo()

Dim IE As New InternetExplorer, iColumns As Object, iRow As Object, i As Long, j As Long, r As Long, c As Long

Application.ScreenUpdating = False

With IE
    .Visible = True
    .navigate "https://rotogrinders.com/team-stats/nba-earned?site=draftkings"

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

    Set iColumns = .document.querySelectorAll(".rgt-col")

    With ThisWorkbook.Worksheets("Sheet1")
        For i = 0 To iColumns.Length - 1
            c = c + 1: r = 0
            Set iRow = iColumns.item(i).getElementsByTagName("div")
            For j = 0 To iRow.Length - 1
                r = r + 1
                .Cells(r, c) = iRow(j).innerText
            Next
        Next
    End With
    Application.ScreenUpdating = True
    .Quit
End With
End Sub

Пожалуйста, имейте в виду, у меня есть ровно 4 дня опыта. Нуб во всех отношениях.

1 Ответ

0 голосов
/ 28 октября 2018

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

Переносимая часть всего этого - это изучение того, как читать HTML, и принятие решения, когда использовать XMLHTTP (который я использую ниже и является более быстрым методом извлечения, но не будет извлекать все со страницы - особенно если страница имеет большой объем JavaScript) по сравнению с решением на основе браузера. Потренируйтесь в использовании инструментов инспекции / разработки, чтобы поиграть с выбором информации.

Тогда есть общие биты кода, которые вы обычно будете использовать каждый раз, например, при использовании IE у вас почти всегда будут одни и те же строки соединения кода и строки ожидания кода. С xmlHttp вы, как правило, также будете повторно использовать вводные строки кода. Но, поскольку веб-сайты, как правило, довольно разные, вам нужно будет изучить, как анализировать DOM каждый раз, чтобы получить нужную информацию. Со страницами, принадлежащими одному и тому же сайту / хосту, вы можете повторно использовать больше кода, если их разработчики последовательны в дизайне своих страниц. Только не ожидайте, что это так.

В приведенном ниже сценарии используется querySelectorAll , в данном случае метод HTMLDocument , для первоначальной генерации nodeLists путем сопоставления элементов по их именам классов .

Эти строки ниже генерируют то, что вы можете считать списками. Каждый элемент в списке имеет одинаковое имя класса.

Set teamsVisitors = .querySelectorAll(".lineup__team.is-visit")
Set teamsHomies = .querySelectorAll(".lineup__team.is-home")
Set nickNamesVisitors = .querySelectorAll(".lineup__mteam.is-visit")
Set nickNamesHomies = .querySelectorAll(".lineup__mteam.is-home")
Set visitors = .querySelectorAll(".lineup__list.is-visit") '  then by li
Set homies = .querySelectorAll(".lineup__list.is-home") ' then by li

Итак, давайте посмотрим на один из этих списков. nodeList, связанный с

Set teamsVisitors = .querySelectorAll(".lineup__team.is-visit")

image

Вы можете видеть, как это собрало 4 буквы из двух букв в команде nodeList (вы могли бы подумать о коллекции, но вы не можете For Each над ней, и на самом деле это больше похоже на массив).

Я дал переменным достаточно описательные имена, чтобы вы знали, что находится в каждом списке, но если вы не уверены, вы можете перейти к инструментам разработчика (F12 в Chrome, FireFox), выделить любой бит HTML на вкладке элементов а затем Ctrl + F , чтобы вызвать окно поиска HTML и ввести текст между "" из querySelectorAll в это поле, например .lineup__team.is-visit

image

Вы видите, что он возвращает количество совпадений в HTML для селектора CSS. Вы можете использовать ввод для их циклического перемещения.

Итак, у меня есть серия nodeList с. Каждый индекс, например Индекс 0, в каждом nodeList, относится к одному совпадению. Итак, по индексу 0 у меня есть GS v BKN i.e. Warriors v Nets.

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

Set visitors = .querySelectorAll(".lineup__list.is-visit") '  then by li
Set homies = .querySelectorAll(".lineup__list.is-home") ' then by li

Взять индекс 0 в visitors nodeList у нас есть:

image

Нам нужна дополнительная информация; простого использования имени класса было недостаточно. Если мы посмотрим на HTML, то увидим, что на самом деле отдельные элементы разделены на li элементов тега списка:

Это означает, что мы можем использовать метод .getElementsByTagName для возврата этих элементов. Например:

homies.item(i).getElementsByTagName("li")

В итоге это выглядит так (пример):

image

В моем цикле я записываю посетителей в левую колонку, а домой справа. Когда я перебираю индексы (то есть каждое совпадение) в исходных nodeList s, я добавляю +3 к номеру выходного столбца, чтобы вы получили разнесенную запись для каждой таблицы.


Пример вывода:

enter image description here


VBA:

Option Explicit
Public Sub GetMatchInfo()
    Dim sResponse As String, html As HTMLDocument
    Application.ScreenUpdating = False

    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", "https://www.rotowire.com/basketball/nba-lineups.php", False
        .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
        .send
        sResponse = StrConv(.responseBody, vbUnicode)
    End With

    Set html = New HTMLDocument

    Dim visitors As Object, teamsVisitors As Object, nickNamesVisitors As Object
    Dim homies As Object, teamsHomies As Object, nickNamesHomies As Object
    Dim i As Long, r As Long, c As Long, j As Long

    With html
        .body.innerHTML = sResponse
        Set teamsVisitors = .querySelectorAll(".lineup__team.is-visit")
        Set teamsHomies = .querySelectorAll(".lineup__team.is-home")
        Set nickNamesVisitors = .querySelectorAll(".lineup__mteam.is-visit")
        Set nickNamesHomies = .querySelectorAll(".lineup__mteam.is-home")
        Set visitors = .querySelectorAll(".lineup__list.is-visit") '  then by li
        Set homies = .querySelectorAll(".lineup__list.is-home") ' then by li
    End With

    With ThisWorkbook.Worksheets("Sheet1")
        r = 1: c = 1

        For i = 0 To teamsHomies.Length - 1
            .Cells(r, c) = teamsVisitors.item(i).innerText
            .Cells(r, c + 1) = teamsHomies.item(i).innerText

            r = r + 1
            .Cells(r, c) = nickNamesVisitors.item(i).innerText
            .Cells(r, c + 1) = nickNamesHomies.item(i).innerText

            Dim numHomiesLiElements As Long, numVisitorsLiElements As Long, maxNumberofLiElements As Long

            numHomiesLiElements = homies.item(i).getElementsByTagName("li").Length - 1
            numVisitorsLiElements = visitors.item(i).getElementsByTagName("li").Length - 1

            maxNumberofLiElements = IIf(numHomiesLiElements > numVisitorsLiElements, numHomiesLiElements, numVisitorsLiElements)
            For j = 0 To maxNumberofLiElements
                r = r + 1
                On Error Resume Next
                .Cells(r, c) = visitors.item(i).getElementsByTagName("li")(j).innerText
                .Cells(r, c + 1) = homies.item(i).getElementsByTagName("li")(j).innerText
                On Error GoTo 0
            Next

            r = 1: c = c + 3
        Next

    End With

    Application.ScreenUpdating = True

End Sub

Ссылки (VBE> Инструменты> Ссылки):

  1. Библиотека объектов Microsoft HTML

Ресурсы, которые могут вам помочь:

  1. getElementsByTagName
  2. Селекторы классов CSS
  3. XMLHTTP-запросы

Смотрите здесь для улучшенного сценария на основе Python:

https://stackoverflow.com/a/55626217/6241235

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...