在回答这个问题时,我注意到一些奇怪的行为。在该答案的代码中,如下所示,我期望变量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
什么?
其他观察:
- 你可以
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 的默认调用。@SMeaden 链接的 QA 状态:
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
通过 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