2

在回答这个问题时,我注意到一些奇怪的行为。在该答案的代码中,如下所示,我期望变量names是静态 nodeList: Object\DispStaticNodeList。这是带有 VBA MSHTML.HTMLDocument 类的querySelectorAll的通常返回。

来自API 文档

Document 方法 querySelectorAll() 返回一个静态(非实时)NodeList,表示与指定选择器组匹配的文档元素列表。

但是,在这种情况下,Locals 中的返回是Object,而使用 TypeName(names) 时是JScriptTypeInfo。我以前读过这篇令人印象深刻的帖子并且非常熟悉,ScriptControl但这并没有向我解释这里发生了什么。

为什么 querySelectorAll 返回一个JScriptTypeInfo对象而不是静态节点列表。为什么这是JScriptTypeInfo特定于querySelectorAll而不是getElementsByClassName?我觉得它一定与类接口有关,但是这个页面导致Object\JScriptTypeInfo而不是Object\DispStaticNodeList什么?


其他观察:

  1. 你可以getElementsByClassName很好地使用:

Set names = .getElementsByClassName("selection-left-selection-name")
'?typename(names) >> DispHTMLElementCollection
  1. 该对象通过了 IsObject 测试并且可以与 Set 一起使用,但随后可以被视为一个字符串:

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

我认为这与返回的实际对象有关,但使用Debug.Print names. 但是为了让它工作,我们假设我们不再获得一个对象数组作为返回。否则,它将被链接到 .defaultMember.defaultMember 的默认调用。@SMeaden 链接的 QA 状态:

JScriptTypeInfo 是在 VBA IDE 监视窗口中显示的内容和 VBA 函数 TypeName() 的返回,但它实际上隐藏了许多可以在 JScript.dll 中找到的对象。我想它可以被描述为多态,也许将其描述为后期绑定更好。要查看功能,请使用 Tools-References 并浏览到 JScript.dll。

在这种情况下,我如何检查默认成员(我在 64 位机器上)?我假设我无法添加 ScriptControl dll,因为我认为它们需要 32 位?这些后来的观点更多的是沉思。

  1. 我想知道这是否与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

通过 Python selenium + IE 的 Css 选择器:

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'>

未经测试的带有 IE 的 VBA 硒(我无法测试):

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
4

0 回答 0