Извлечение серии URL с использованием VBA - PullRequest
0 голосов
/ 29 сентября 2018

Я просто пытаюсь запустить список URL-ссылок, но он продолжает показывать ошибку времени выполнения '91 ', переменную объекта или переменную блока не задано.

Данные, которые я хочу извлечь, взяты из iframes,Он действительно показывает некоторые значения, но застрял в середине процесса с ошибкой.

Ниже приведена примерная ссылка URL, из которой я хочу извлечь значение: http://www.bursamalaysia.com/market/listed-companies/company-announcements/5927201

Public Sub GetInfo()
    Dim IE As New InternetExplorer As Object
    With IE
        .Visible = False

        For u = 2 To 100

        .navigate Cells(u, 1).Value

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



        With .document.getElementById("bm_ann_detail_iframe").contentDocument
            ThisWorkbook.Worksheets("Sheet1").Cells(u, 3) = .getElementById("main").innerText
            ThisWorkbook.Worksheets("Sheet1").Cells(u, 4) = .getElementsByClassName("company_name")(0).innerText
            ThisWorkbook.Worksheets("Sheet1").Cells(u, 5) = .getElementsByClassName("formContentData")(0).innerText
            ThisWorkbook.Worksheets("Sheet1").Cells(u, 6) = .getElementsByClassName("formContentData")(5).innerText
            ThisWorkbook.Worksheets("Sheet1").Cells(u, 7) = .getElementsByClassName("formContentData")(7).innerText
            ThisWorkbook.Worksheets("Sheet1").Cells(u, 8) = .getElementsByClassName("formContentData")(8).innerText
            ThisWorkbook.Worksheets("Sheet1").Cells(u, 9) = .getElementsByClassName("formContentData")(9).innerText
            ThisWorkbook.Worksheets("Sheet1").Cells(u, 10) = .getElementsByClassName("formContentData")(10).innerText
            ThisWorkbook.Worksheets("Sheet1").Cells(u, 11) = .getElementsByClassName("formContentData")(11).innerText
       End With

    Next u
    End With
End Sub

1 Ответ

0 голосов
/ 29 сентября 2018

tl; dr

Ваша ошибка связана с тем, что для данного имени класса имеется разное количество элементов в зависимости от результатов на странице.Таким образом, вы не можете использовать фиксированные индексы.Для страницы, которую вы указали, последний индекс для этого класса через iframe равен 9, т.е. ThisWorkbook.Worksheets("Sheet1").cells(u, 9) = .getElementsByClassName("formContentData")(9).innerText.10 и 11 недействительны.Ниже я показываю способ определения количества результатов и извлечения информации из каждой строки результатов.

Общий принцип:

Хорошо ... так что следующее работает надпринцип нацеливания на таблицу Details of Changes для большей части информации.

Пример извлечения:

image

Более конкретно, я нацеливаюсь на строки, которые повторяют информацию для No, Date of Change, #Securities, Type of Transaction and Nature of Interest.Эти значения хранятся в массиве массивов (один массив на строку информации).Затем массивы результатов сохраняются в коллекции для последующей записи на лист.Я заполняю каждую ячейку таблицы в целевых строках (td элементы тега в родительском tr), чтобы заполнить массивы.

Я добавляю Name из таблицы выше на странице, а также, потому чтов зависимости от веб-страницы может быть несколько строк результатов, и поскольку я записываю результаты на новый лист Results, я добавляю URL перед каждым результатом, чтобы указать источник информации.


TODO:

  1. Изменить код на более модульный
  2. Потенциально добавить в некоторую обработку ошибок

CSS селекторы:


select Я выбираю элемент Name, который я называю title, из таблицы Particulars of substantial Securities Holder.

ПримерЭлемент name:

enter image description here

Проверка HTML для этого элемента показывает, что он имеет класс formContentLabel, ичто это первый класс с этим значением на странице.

Пример HTML-кода для целевого имени:

enter image description here

Это означает, что я могу использовать селектор класса , .formContentLabel, для нацеливания на элемент.Поскольку это единственный элемент, я хочу использовать метод querySelector для применения селектора CSS.


target Я нацеливаю интересующие строки в таблице Details of Changes с помощью комбинации селекторов .ven_table tr.Это комбинация потомок , объединяющая элементы выбора с тегом tr, имеющим родителя с классом ven_table.Поскольку это несколько элементов, я использую метод querySelectorAll, чтобы применить комбинацию селекторов CSS.

Пример целевой строки:

enter image description here

Пример результатов, возвращаемых селектором CSS (образец):

enter image description here

Интересующие меня строки начинаются с 1 и повторяются каждые + 4 строки, например, после строк 5, 9 и т. Д. Поэтому я использую небольшую математику в коде, чтобы вернуть только интересующие строки:

Set currentRow = data.item(i * 4 + 1)

VBA:

Option Explicit
Public Sub GetInfo()
    Dim IE As New InternetExplorer, headers(), u As Long, resultCollection As Collection
    headers = Array("URL", "Name", "No", "Date of change", "# Securities", "Type of Transaction", "Nature of Interest")
    Set resultCollection = New Collection
    Dim links()
    links = Application.Transpose(ThisWorkbook.Worksheets("Sheet1").Range("A2:A3")) 'A100

    With IE
        .Visible = True

        For u = LBound(links) To UBound(links)
            If InStr(links(u), "http") > 0 Then
                .navigate links(u)

                While .Busy Or .readyState < 4: DoEvents: Wend
                Application.Wait Now + TimeSerial(0, 0, 1) '<you may not always need this. Or may need to increase.
                Dim data As Object, title As Object
                With .document.getElementById("bm_ann_detail_iframe").contentDocument
                    Set title = .querySelector(".formContentData")
                    Set data = .querySelectorAll(".ven_table tr")
                End With

                Dim results(), numberOfRows As Long, i As Long, currentRow As Object, td As Object, c As Long, r As Long

                numberOfRows = Round(data.Length / 4, 0)
                ReDim results(1 To numberOfRows, 1 To 7)

                For i = 0 To numberOfRows - 1
                    r = i + 1
                    results(r, 1) = links(u): results(r, 2) = title.innerText
                    Set currentRow = data.item(i * 4 + 1)
                    c = 3
                    For Each td In currentRow.getElementsByTagName("td")
                        results(r, c) = Replace$(td.innerText, "document.write(rownum++);", vbNullString)
                        c = c + 1
                    Next td
                Next i
                resultCollection.Add results
                Set data = Nothing: Set title = Nothing
            End If
        Next u
        .Quit
    End With
    Dim ws As Worksheet, item As Long
    If Not resultCollection.Count > 0 Then Exit Sub

    If Not Evaluate("ISREF('Results'!A1)") Then '<==Credit to @Rory for this test
        Set ws = Worksheets.Add
        ws.NAME = "Results"
    Else
        Set ws = ThisWorkbook.Worksheets("Results")
        ws.cells.Clear
    End If

    Dim outputRow As Long: outputRow = 2
    With ws
        .cells(1, 1).Resize(1, UBound(headers) + 1) = headers
        For item = 1 To resultCollection.Count
            Dim arr()
            arr = resultCollection(item)
            For i = LBound(arr, 1) To UBound(arr, 1)
                .cells(outputRow, 1).Resize(1, 7) = Application.WorksheetFunction.Index(arr, i, 0)
                outputRow = outputRow + 1
            Next
        Next
    End With
End Sub

Пример результатов с использованием 2 предоставленных тестовых URL:

enter image description here


Примеры URL-адресов в листе 1:

  1. http://www.bursamalaysia.com/market/listed-companies/company-announcements/5928057
  2. http://www.bursamalaysia.com/market/listed-companies/company-announcements/5927201
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...