Отправка HTTP-запроса с использованием библиотеки MS XML, 6.0 с динамическим/частично известным URL-циклом

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

Например, если посмотреть журналы игр Мартина Переса за 2024 год, URL-адрес: https://www.statmuse.com/mlb/player/martin-perez-46483/game-log

теперь при попытке пройти через разных питчеров эта 5-значная числовая последовательность (46483 в моем примере) является переменной и меняется в журнале игры каждого питчера.

Я собрал приведенный ниже код. Проблема, конечно же, заключается в циклическом переборе 10000 и 99999 в попытке найти правильную последовательность пятизначных чисел, из-за чего мой Excel выходит из строя и не отвечает. Может ли кто-нибудь посоветовать более эффективный способ добиться этого? Прошу прощения, это мой первый проект с HTTP-запросами и чем-то подобным, поэтому я уверен, что код — это чертовски беспорядок.

код:

Dim ws As Worksheet, PLws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
Set PLws = ThisWorkbook.Sheets("Pitcher List T")

Set rng = PLws.Range("B1:B1")
For Each cc In rng

    Dim httpRequest As MSXML2.XMLHTTP60:    Set httpRequest = New MSXML2.XMLHTTP60
    Dim htmldoc As HTMLDocument:            Set htmldoc = New HTMLDocument
    
    playerName = CStr(cc.Value)
    Dim baseURL As String
    baseURL = "https://www.statmuse.com/mlb/player/" & playerName & "-"

    Dim lastRow As Long
    Dim startNumber As Long
    Dim endNumber As Long
    startNumber = 10000 ' this loop is the issue (i think)
    endNumber = 99999   ' this loop is the issue (i think)

Dim i As Long, target As Long
For i = startNumber To endNumber ' this loop is the issue (i think)

    Dim url As String
    url = baseURL & CStr(i) & "/game-log"
    
    If CheckUrlExists(url) Then
        target = i
        Debug.Print "the target i is: " & target
    End If

Next i
    
    Dim Murl As String
    Murl = baseURL & target & "/game-log"
    
    httpRequest.Open "GET", Murl, False
    httpRequest.send
    htmldoc.body.innerHTML = httpRequest.responseText

это функция:

Public Function CheckUrlExists(url) As Boolean
        
    On Error GoTo CheckUrlExists_Error
    
    Dim xmlhttp As MSXML2.XMLHTTP60:    Set xmlhttp = New MSXML2.XMLHTTP60
    Dim htmldoc As HTMLDocument:            Set htmldoc = New HTMLDocument
    Dim H2el As Object
    
    xmlhttp.Open "GET", url, False
    xmlhttp.send
    htmldoc.body.innerHTML = xmlhttp.responseText
    
    If xmlhttp.Status = 200 Then
        For Each H2el In htmldoc.getElementsByTagName("h2")
            If InStr(1, ChangeAccent(H2el.innerText), CStr(cc.Offset(0, -1).Value)) > 0 Then
                CheckUrlExists = True
            End If
        Next H2el
    Else
        CheckUrlExists = False
    End If
    
    Exit Function
    
CheckUrlExists_Error:
    CheckUrlExists = False
    
End Function

Спасибо

Пожалуйста, поделитесь кодом в Function CheckUrlExists().

taller 10.05.2024 01:03

я обновил вопрос, включив в него функцию

Kurt 10.05.2024 01:20

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

Tim Williams 10.05.2024 02:33

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

Kurt 10.05.2024 04:08

Не могли бы вы указать мне правильное направление, как правильно отправить запрос? И, если возможно, как получить URL-адрес с подстановочными знаками, не повреждая сайт и не отправляя слишком много запросов?

Kurt 10.05.2024 04:46
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
1
5
97
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

  • Порядковый номер в URL-адресе не всегда состоит из 5 цифр. например.

https://www.statmuse.com/nba/player/lebron-james-1780

  • Для каждого запроса POST время ответа удаленного сервера для кодов состояния 200 (ОК) или 502 (Плохой шлюз) различается. В моем тестировании это обычно занимает от полсекунды до одной секунды. Проверка 90 000 URL-адресов с помощью этого метода нецелесообразна.

  • Действительно, попытка проверки большого количества URL-адресов может создать значительную нагрузку на серверы веб-сайта. Фактически, это можно интерпретировать как форму незначительной DDoS-атаки (распределенный отказ в обслуживании).

  • Приведенный ниже код имитирует search на https://www.statmuse.com/ с использованием Internet Explorer, который, хотя и немного устарел, но все же выполняет свою работу. Selenium WebDriver может быть лучшей альтернативой.

Sub Demo()
    Debug.Print GetURL("martin perez")
    Debug.Print GetURL("lebron james")
End Sub
Function GetURL(ByVal sFullName As String) As String
    Dim IE As Object
    Dim doc As Object
    ' Initialize Internet Explorer
    Set IE = CreateObject("InternetExplorer.Application")
    IE.Visible = False
    ' Navigate to the webpage
    IE.Navigate "https://www.statmuse.com/ask?q = " & Replace(sFullName, " ", "-")
    ' Wait for IE to finish loading the page
    Do While IE.Busy Or IE.readyState <> 4
        DoEvents
    Loop
    ' Get the document object
    Set doc = IE.Document
    ' Get the HTML content of the webpage
    'Dim htmlContent As String:  htmlContent = doc.DocumentElement.outerHTML
    Dim oLink As Object
    Set oLink = doc.getElementsByTagName("link")(0)
    ' Extract the href attribute value from the link tag
    If Not oLink Is Nothing Then
        GetURL = oLink.getAttribute("href")
    Else
        GetURL = ""
    End If
    ' Close IE
    IE.Quit
    Set IE = Nothing
End Function

Вывод в немедленном окне:

https://www.statmuse.com/mlb/player/mart%C3%ADn-p%C3%A9rez-46483
https://www.statmuse.com/nba/player/lebron-james-1780

спасибо, я получил ошибку во время выполнения «ошибка автоматизации, вызванный объект отключился от своих клиентов» в строке «Do While IE.Busy Or IE.readyState <> 4», и я включил соответствующие ссылки для элементов управления IE.

Kurt 10.05.2024 15:13

Я не уверен, что означает ошибка. Я протестировал код без проблем на Win11+O365.

taller 10.05.2024 17:30
Ответ принят как подходящий

Просто получите URL-адрес напрямую с помощью:

Function GetPlayerLogURLs(ByRef playerName As Variant) As Collection
    Dim httpRequest As MSXML2.XMLHTTP60: Set httpRequest = New MSXML2.XMLHTTP60
    Const baseURL As String = "https://www.statmuse.com"
    '
    httpRequest.Open "POST", baseURL & "/ask", False
    httpRequest.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
    httpRequest.send "question%5Bquery%5D = " _
                   & LCase$(Replace(playerName, " ", "+")) _
                   & "&question%5Bpreferred_domain%5D=&question%5Bconversation_token%5D = "
    '
    Dim response As String: response = httpRequest.responseText
    Dim i As Long
    Dim j As Long
    Dim res As New Collection
    Dim temp As String
    '
    i = InStr(1, response, "/game-log""")
    If i = 0 Then
        i = InStr(1, response, """/mlb/player/")
        On Error Resume Next
        Do While i > 0
            j = InStr(i + 1, response, """")
            If j > 0 Then
                temp = baseURL & Mid$(response, i + 1, j - i - 1) & "/game-log"
                res.Add temp, temp
            End If
            i = InStr(j + 1, response, """/mlb/player/")
        Loop
        On Error GoTo 0
    Else
        j = InStrRev(response, """", i)
        If j > 0 Then res.Add baseURL & Mid$(response, j + 1, i - j + 8)
    End If
    Set GetPlayerLogURLs = res
End Function

а затем просто используйте его вот так:

Sub TestPlayerURLs()
    Dim v As Variant
    Dim w As Variant
    Dim coll As Collection
    '
    For Each v In Array("Martin Perez", "Derrick White", "Logan Allen", "This name doesn't exist")
        Debug.Print "Player name: " & v
        Set coll = GetPlayerLogURLs(v)
        Debug.Print "Results found: " & coll.Count
        For Each w In coll
            Debug.Print w
        Next w
        Debug.Print
    Next v
End Sub

если у вас есть время, не могли бы вы ответить еще на один вопрос. Как мне учитывать, есть ли игроки с таким же именем? Например. Логан Аллен о «Даймондбэках» (statmuse.com/mlb/player/logan-allen-90330/game-log ) и Логан Аллен о «Стражах» ( statmuse.com/mlb/player/logan-allen-92509 /game-log)? В данный момент функция в этом сценарии ничего не возвращает, я предполагаю, что существует несколько результатов. Спасибо за ваше время.

Kurt 10.05.2024 16:03

@Курт, я отредактировал ответ. функция теперь возвращает объект Collection с 0, 1 или несколькими ответами.

Cristian Buse 10.05.2024 17:50

@CristianBuse Очень изящное решение. Могу я задать простой вопрос: как разобраться в аргументе send ? например. "&question%5Bpreferred_domain%5D=&question%5Bconversation_to‌​ken%5D = " в вашем коде.

taller 10.05.2024 18:01

@taller Конечно. В своем браузере используйте инструменты разработчика. Для Chrome нажмите клавишу F12. Затем перейдите на вкладку «Сеть» и начните запись. Затем, какие бы действия вы ни совершали, они записываются, и вы можете затем просмотреть каждый запрос GET или POST. Вы сможете увидеть заголовки запросов, URL-адреса, содержимое форм, ответы и т. д.

Cristian Buse 10.05.2024 18:32

@CristianBuse Есть идеи, почему сегодня утром у меня это работало идеально, а теперь, примерно через час тестирования и адаптации результатов к моему листу, он не возвращает URL-адрес даже в простом тесте debug.print?

Kurt 10.05.2024 19:21

@Курт, я только что проверил, и у меня все еще работает. Должно быть, вы выполнили слишком много запросов за короткий период времени. Попробуйте изменить свой IP-адрес, например. используйте VPN

Cristian Buse 10.05.2024 19:40

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