Excel VBA и HTML DOM: не могу щелкнуть вкладку

В Excel 2003 VBA я пытаюсь перейти на эту веб-страницу...

https://www.google.com/finance?q=NYSE%3AWSO&fstype=ii&ei=cy30UrCEI8KKiALOPw

...и откройте на нем две вкладки:
- "Балансовый отчет"
- "Годовые данные"

Вот как выглядит HTML для этих вкладок:
<a class=t><b class=t><b class=t>Balance Sheet</b></b></a>
и
<a id=annual class="id-annual nac">Annual Data</a>

Поиск годовых данных с помощью getElementById и нажатие на них работали нормально.

Но балансовый отчет не имеет идентификатора. Использование getElementByClass было бы неоднозначным с более чем одним элементом с именем класса "t". И, похоже, нет getElementByInnerText или getElementByInnerHTML.

Итак, я просмотрел все элементы, ища имя класса «t», а затем искал innerText «Балансовый отчет». Я могу найти элемент (три из них, что, я думаю, ожидается, учитывая его структуру), НО щелчок по нему не дает никакого эффекта (я пытался щелкнуть все три).

Но когда я попробовал этот метод с годовыми данными, он работал нормально.

Что мне нужно сделать, чтобы иметь возможность щелкнуть вкладку «Баланс»? Я почти уверен, что нашел его; просто не удачно нажав на него.

Вот мой код:

Option Explicit

Sub TestMain()

    Dim strURL As String

    strURL = "https://www.google.com/finance?q=NYSE%3AWSO&fstype=ii&ei=cy30UrCEI8KKiALOPw"

    Call Main(strURL)

End Sub


Function Main(url_string As String)

    Dim oIE As Object, oDoc As Object, oElem As Object

    Set oIE = CreateObject("InternetExplorer.Application")

    oIE.Visible = True

    oIE.Navigate url_string
        Do While oIE.Busy
            Application.Wait DateAdd("s", 1, Now)
        Loop

    Set oDoc = oIE.document

    'Annual Data tab:
    Set oElem = GetElementsByClassNameAndInnerText(oDoc, "id-annual", True, "Annual Data", False)
    oElem.Click 'this works.

    'Quarterly Data:
    Set oElem = GetElementsByClassNameAndInnerText(oDoc, "id-interim", True, "Quarterly Data", False)
    oElem.Click 'this works.

    'Balance Sheet:
    Set oElem = GetElementsByClassNameAndInnerText(oDoc, "t", False, "Balance Sheet", True)
    oElem.Click 'does NOT work.

    'Income Statement:
    Set oElem = GetElementsByClassNameAndInnerText(oDoc, "t", False, "Income Statement", True)
    oElem.Click 'does NOT work.

    oIE.Quit
    Set oIE = Nothing

End Function


Public Function GetElementsByClassNameAndInnerText(html_doc As Object, _
                                                   class_name As String, is_classname_partial As Boolean, _
                                                   inner_text As String, is_innertext_partial As Boolean) As Object
    Dim oElem As Object
    Dim bClassNameIsMatch As Boolean, bInnerTextIsMatch As Boolean


    For Each oElem In html_doc.All
'        Debug.Print oElem.GetAttribute("class"), oElem.innertext
        bClassNameIsMatch = False 'init for each oElem.

        If is_classname_partial Then
            If InStr(oElem.GetAttribute("class"), class_name) > 0 Then
                bClassNameIsMatch = True
            End If
        Else
            'classname is exact:
            If oElem.GetAttribute("class") = class_name Then
                bClassNameIsMatch = True
            End If
        End If

        If bClassNameIsMatch Then
            bInnerTextIsMatch = False 'init for each oElem.

            If is_innertext_partial Then
                If InStr(oElem.innertext, inner_text) > 0 Then
                    bInnerTextIsMatch = True
                End If
            Else
                'innertext is exact:
                If oElem.innertext = inner_text Then
                    bInnerTextIsMatch = True
                End If
            End If

            If bInnerTextIsMatch Then
                If oElem.innertext = inner_text Then
                    Set GetElementsByClassNameAndInnerText = oElem
                    Exit For
                End If
            End If

        End If

    Next oElem
End Function

Спасибо,

Грег


person Greg Lovern    schedule 09.02.2014    source источник
comment
Если я перейду на эту страницу, то отчет о прибылях и убытках будет не кликабельной ссылкой, а просто жирным шрифтом, так как он уже выбран по умолчанию. И источник, который я вижу (по крайней мере, в IE11), не похож на HTML в вашем вопросе.   -  person Tim Williams    schedule 09.02.2014
comment
@Tim Williams: мне нужно перейти на вкладки «Баланс» и «Отчет о прибылях и убытках». Я просто погуглил в вопросе о том, какой из них был по умолчанию. В моем коде я пытаюсь добраться до обоих. Я исправлю вопрос. ..... Я также использую IE11; это 11.0.9600.16476. Как для вас выглядит источник этих вкладок? Они находятся в строках 116 и 128.   -  person Greg Lovern    schedule 09.02.2014


Ответы (2)


Я не могу найти способ щелкнуть эти вкладки программно. Данные, по крайней мере, таблицы, могут быть загружены, хотя, поскольку вкладки используются только для выбора видимого раздела, все данные находятся на странице. В следующей функции 6 разделов копируются в файл (можно очистить, написав для этого функцию). Затем IE перенаправляется на этот файл.

Если это то, что вы хотите сделать, возможно, вам лучше взглянуть на Microsoft HTML Object Library или XML вместо IE и использовать get ot post для получения данных.

Я использовал ссылки на библиотеку объектов Microsoft HTML, средства управления Интернетом Microsoft и среду выполнения сценариев Microsoft для этой функции.

Function main(url_string As String)

    Dim oIE As InternetExplorer
    Dim oDivElement As HTMLDivElement
    Dim fsoObject As Scripting.FileSystemObject
    Dim FileHandle As Scripting.TextStream


    Set oIE = CreateObject("InternetExplorer.Application")

    oIE.Visible = True

    oIE.navigate url_string
    Do While oIE.Busy
       Application.Wait DateAdd("s", 1, Now)
    Loop

    Set fsoObject = New FileSystemObject
    Set FileHandle = fsoObject.CreateTextFile((ThisWorkbook.Path & "\Output.html"), True)


    Set oDivElement = oIE.document.getElementById("incinterimdiv")
    FileHandle.WriteLine ("Quarterly income")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine (oDivElement.innerHTML)
    Set oDivElement = oIE.document.getElementById("incannualdiv")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine ("Annual income")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine (oDivElement.innerHTML)
    Set oDivElement = oIE.document.getElementById("balinterimdiv")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine ("Quarterly balance")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine (oDivElement.innerHTML)
    Set oDivElement = oIE.document.getElementById("balannualdiv")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine ("Annual balance")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine (oDivElement.innerHTML)
    Set oDivElement = oIE.document.getElementById("casinterimdiv")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine ("Quarterly cash flow")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine (oDivElement.innerHTML)
    Set oDivElement = oIE.document.getElementById("casannualdiv")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine ("Annual cash flow")
    FileHandle.WriteLine ("<BR>&nbsp;<BR>")
    FileHandle.WriteLine (oDivElement.innerHTML)

    FileHandle.Close
    Set FileHandle = Nothing
    Set fsoObject = Nothing
    Set oDivElement = Nothing
    Set oIE = Nothing

End Function
person Graham Anderson    schedule 10.02.2014
comment
Спасибо! Я делаю это сейчас таким образом, и это работает отлично. Следующий вопрос: «Могу ли я заставить это или что-то подобное работать в Macintosh Excel?» но я создам новую тему для этого вопроса. - person Greg Lovern; 12.02.2014

Это помогает мне. Просмотрите код после загрузки веб-страницы, чтобы увидеть, что происходит.

Sub test()
    URL = "https://www.google.com/finance?q=NYSE%3AWSO&fstype=ii&ei=cy30UrCEI8KKiALOPw"

    Set IE = CreateObject("InternetExplorer.Application")
        IE.Visible = True
        IE.navigate URL

    Do Until (IE.readyState = 4 And Not IE.Busy)
        DoEvents
    Loop

' This will 1) "unclick" "the Income Statement" sheet tab and 2) "click" the "Balance Sheet" tab;
' the data below doesn't change, just the tab
    IE.document.getElementbyID(":0").classname = "goog-tab"
    IE.document.getElementbyID(":1").classname = "goog-tab goog-tab-selected"

' This will change the data below the tabs
    IE.document.getElementbyID("incinterimdiv").setAttribute("Style") = "display: none;"
    IE.document.getElementbyID("balinterimdiv").setAttribute("Style") = ""

    IE.document.getElementbyID("balinterimdiv").setAttribute("Style") = "display: none;"
    IE.document.getElementbyID("casinterimdiv").setAttribute("Style") = ""

    IE.document.getElementbyID("incinterimdiv").setAttribute("Style") = ""
    IE.document.getElementbyID("casinterimdiv").setAttribute("Style") = "display: none;"
End Sub
person ron    schedule 11.02.2014
comment
Спасибо, это выглядит здорово! Я только что закончил фазу проекта, используя решение Грэма ниже, поэтому я просто буду придерживаться этого. Интересно, что щелчок по вкладке и обмен данными должны быть разными командами. - person Greg Lovern; 12.02.2014