Почему querySelectorAll возвращает объект, который является JScriptTypeInfo, который затем может быть обработан как строка, а не nodeList? - PullRequest
1 голос
/ 20 сентября 2019

Отвечая на этот вопрос, я заметил какое-то странное для меня поведение.В коде из этого ответа, показанном ниже, я ожидал, что переменные names будут статическими nodeList: Object\DispStaticNodeList.Это обычный возврат для querySelectorAll с классом VBA MSHTML.HTMLDocument.

Из документации API

Метод Document querySelectorAll () возвращает статический (не действующий) NodeList, представляющий список элементов документа, которые соответствуют указанной группе селекторов.

Однако в этом случае возвращаемое значение в Locals равно Object, и при использованииИмя типа (имена) - JScriptTypeInfo.Ранее я читал этот впечатляющий пост и немного знаком с ScriptControl, но это не объясняет мне, что здесь происходит.

Почему querySelectorAll возвращает JScriptTypeInfo объектвместо статического nodeList.И почему это JScriptTypeInfo характерно для querySelectorAll, а не getElementsByClassName?Я чувствую, что это должно быть связано с интерфейсами классов, но что на этой странице приводит к Object\JScriptTypeInfo, а не Object\DispStaticNodeList?


Другие наблюдения:

  1. Вы можете использовать getElementsByClassName очень хорошо:

Set names = .getElementsByClassName("selection-left-selection-name")
'?typename(names) >> DispHTMLElementCollection
Объект проходит тест IsObject и может использоваться с Set, но впоследствии может рассматриваться как строка:

Debug.Print IsObject(names)  '>> True
Debug.Print names    '>> "[object HTMLDivElement],[object HTMLDivElement],[object HTMLDivElement],....."

Я предполагаю, что это как-то связано свозвращается реальный объект, но по умолчанию вызывается элемент с Debug.Print names.Но чтобы это работало, мы предполагаем, что больше не получаем массив объектов в качестве возврата.В противном случае это будет цепочка вызова по умолчанию .defaultMember.defaultMember.Связанный QA от @SMeaden гласит:

JScriptTypeInfo - это то, что нужно показать в окне просмотра VBA IDE и возвращении функции VBA TypeName (), но которая действительно скрывает ряд объектов, которые можно найтив JScript.dll.Я полагаю, это можно назвать полиморфным, возможно, лучше описать его как позднее связывание.Для просмотра возможностей используйте Tools-References и перейдите к JScript.dll.

В таком случае, как я могу проверить элемент по умолчанию (я на 64-битной машине)?Я предполагаю, что не могу добавить в ScriptControl dll, так как я думаю, что они требуют 32 бит?Эти более поздние пункты - больше размышлений.

Мне было интересно, связано ли это с querySelectorAll с использованием селекторов css, но я заметил следующее: С Python selenium + IE с использованием селекторов Css (так как я не могу тестировать с VBA Selenium Basic), я не вижу такого поведения, хотяРеализация класса webElement.Я получаю ожидаемое <class 'list'> в качестве возврата.Я включаю скрипт для VBA selenium, который я не могу проверить, но должен работать как тест для запуска других.

Код для воспроизведения:

Option Explicit

Public Sub GetOddsIE()
    Dim d As InternetExplorer, names As Object, t as Date, button As Object, ws As Worksheet

    Const MAX_WAIT_SEC As Long = 10
    Set d = New InternetExplorer
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    Const URL = "https://sports.ladbrokes.com/en-af/betting/golf/golf-all-golf/us-masters/2020-us-masters/228648232/"

    With d
        .Visible = True
        .Navigate2 URL
        While .Busy Or .ReadyState <> 4: DoEvents: Wend

        With .Document
            t = Timer
            Do
                DoEvents
                On Error Resume Next
                Set button = .querySelector(".expandable-below-container-button span")
                On Error GoTo 0
                If Timer - t > MAX_WAIT_SEC Then Exit Do
            Loop While button Is Nothing         'wait for element to be present
            If button Is Nothing Then Exit Sub
            button.Click                         'click on show more

            Set names = .querySelectorAll(".selection-left-selection-name")
            Debug.Print IsObject(names)
            Debug.Print TypeName(names)
            Debug.Print names        
          End With             
        Stop
        .Quit
    End With
End Sub

Css селекторы через Python selenium + IE:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

d = webdriver.Ie()
d.get('https://sports.ladbrokes.com/en-af/betting/golf/golf-all-golf/us-masters/2020-us-masters/228648232/')
WebDriverWait(d,10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".expandable-below-container-button"))).click()
names = d.find_elements_by_css_selector('.selection-left-selection-name')
print(type(names))
d.quit()

Дает

>> <class 'list'>

непроверенный VBA селен с IE (я не могу проверитьэто):

Public Sub GetOdds() 'Not tested
    Dim d As WebDriver, names As Object, button As Object, t As Date
    Set d = New IEDriver
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    Const URL = "https://sports.ladbrokes.com/en-af/betting/golf/golf-all-golf/us-masters/2020-us-masters/228648232/"

    With d
        .Start "Chrome"
        .get URL
        t = Timer
        Do
            DoEvents
            On Error Resume Next
            Set button = .FindElementByCss(".expandable-below-container-button span")
            On Error GoTo 0
            If Timer - t > MAX_WAIT_SEC Then Exit Do
        Loop While button Is Nothing
        If button Is Nothing Then Exit Sub
        Set names = .FindElementsByCss(".selection-left-selection-name")
        Debug.Print IsObject(names)
        Debug.Print names.Text '<should fail if webElementsCollection
        Stop
        .Quit
    End With
End Sub
...