【问题标题】:What are the currently supported CSS selectors available to VBA?VBA 目前支持的 CSS 选择器有哪些?
【发布时间】:2021-08-17 21:41:11
【问题描述】:

早在 2021 年 5 月 19 日,我写了 this Q&A 关于最近(4 月 21 日)对与 mshtml.dll 和后期绑定引用相关的界面的可疑更改。如果你愿意,这是第 2 部分。

之前,在诸如thisthis 之类的问题中,我曾说过mshtml.dll 对各种CSS 选择器缺乏支持,尤其是pseudo-classes。在上述问题中,我强调了nth-child()nth-of-type() 没有针对MSHTML 实现。

通常,如 here 所示,不支持的选择器语法会导致:

运行时错误“-2140143604 (8070000c)”:无法完成 由于错误 8070000c 导致的操作。

我预计有些事情会中断,因为不再支持与 Internet Explorer (IE) 相关的各种版本/平台(MSHTML 与之相关 - 请参阅我的 this。我没想到的 to find 是受支持的 CSS 选择器的最新改进。举个例子:

Option Explicit

''Required references:
'' Microsoft HTML Object Library

Public Sub CssTest()

    Const URL = "https://books.toscrape.com/"
    Dim html As MSHTML.HTMLDocument
   
    Set html = New MSHTML.HTMLDocument

    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", URL, False
        .send
        html.body.innerHTML = .responseText
    End With
    
    Debug.Print html.querySelector("meta:nth-of-type(2)").outerHTML
    
End Sub

在 21 年 4 月至 5 月之前,由于使用了未实现的语法,这可能会出错。 现在,在我的设置中,我在 5 月初(最新)期间看到了对 mshtml.dll 的更新,我得到的结果与我通过已支持的自动 Internet Explorer 实例运行它时的结果相同:

<meta name="created" content="24th Jun 2016 09:29">

那么,目前支持 VBA 的 CSS 选择器有哪些?

我已经涵盖了“我们为什么要关心?”在之前的问答中,这里不再赘述。但是,我将重新说明我的设置:

我的设置:

OS Name Microsoft Windows 10 Pro
Version 10.0.19042 Build 19042
System Type x64-based PC
Microsoft® Excel® 2019 MSO (16.0.13929.20206) 32-bit (Microsoft Office Professional Plus)
Version 2104 Build 13929.20373
mshtml.dll file  11.00.19041.985
ieframe.dll file 11.0.19041.964

反馈:

与之前的 Q&A 一样,如果对设置有/没有看到这些更改的任何反馈,我将不胜感激。我将对此添加反馈以供其他人参考。

【问题讨论】:

    标签: vba css-selectors mshtml queryselector


    【解决方案1】:

    tl;dr;

    对 css 选择器和 Element.querySelector 的支持要大得多(允许更灵活地链接 querySelector(All) 调用。这极大地增强了 MSHTML 类在 CSS 选择器方面的表现力,并带来了与Selenium Basic相提并论。


    动机:

    一段时间以来,由于缺乏与 VBA 相关的文档,以及学习什么有效和无效的反复试验性质,我一直想写一份支持的选择器列表。这个最新的变化促使我这样做,并在其中包含当前支持使用 CSS 选择器的那些库。


    注意事项:

    1. 这并不详尽;很全面。
    2. 如果您发现任何错误,尤其是关于 Selenium Basic 的错误,我必须凭记忆编写,请通知我,我会进行相应的编辑。
    3. 最近的更改,由汇总表中的阴影单元格表示 (JSFiddle)|在下面的简化表中,用 ✔* 标记,它们与我的设置有关,在这个时间点。您的里程可能会有所不同,例如 根本不支持 CSS 选择器

    之前和之后:

    传统上,VBA 中 CSS 选择器的表达能力如下,相对于支持它们的库:

    到目前为止,Selenium 实现了最多的 CSS 选择器。

    当前状态:

    我认为当前实现的选择器状态如下(对于图像质量,即使您点击放大表格,请参阅JSFiddle 以获得最清晰的表格视图):

    我也将其作为简化的 HTML 插入包含在内,因此您可以单击超链接。请点击插入代码下方的Run code sn-p,然后点击Full page链接。抱歉,表格很大,我什至没有涵盖所有可以想象的选择器——只有我认为可能经常使用的主要选择器。插入一张精美的桌子让我超过了身体字符的限制,所以我们到了。如需精美的桌子,请参阅此JSFiddle - 新支持的有阴影。

    <!DOCTYPE html>
    <html>
    <head>
        <title>VBA: Valid CSS Selectors 2021-05-30</title>
    </head>
    <body>
        <h1>VBA: Valid CSS Selectors 2021-05-30</h1>
        <table>
            <tr>
                <td colspan="2">
                    <a href="https://drafts.csswg.org/selectors-3/">Selectors Level 3 Specification</a>
                </td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td>Pattern</td>
                <td>Represents</td>
                <td>Description</td>
                <td>Level</td>
                <td>Microsoft HTML Object Library (MSHTML)</td>
                <td>Microsoft Internet Explorer Controls (SHDocVw)</td>
                <td>Selenium Type Library (Selenium)</td>
                <td>Remarks</td>
            </tr>
            <tr>
                <td>*</td>
                <td>any element</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#universal-selector">Universal selector</a>
                </td>
                <td>2</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E</td>
                <td>an element of type E</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#type-selectors">Type selector</a>
                </td>
                <td>1</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E[foo]</td>
                <td>an E element with a "foo" attribute</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#attribute-selectors">Attribute selectors</a>
                </td>
                <td>2</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E[foo="bar"]</td>
                <td>an E element whose "foo" attribute value is exactly equal to "bar"</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#attribute-selectors">Attribute selectors</a>
                </td>
                <td>2</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E[foo~="bar"]</td>
                <td>an E element whose "foo" attribute value is a list of whitespace-separated values, one of which is exactly equal to "bar"</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#attribute-selectors">Attribute selectors</a>
                </td>
                <td>2</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E[foo^="bar"]</td>
                <td>an E element whose "foo" attribute value begins exactly with the string "bar"</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#attribute-selectors">Attribute selectors</a>
                </td>
                <td>3</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E[foo$="bar"]</td>
                <td>an E element whose "foo" attribute value ends exactly with the string "bar"</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#attribute-selectors">Attribute selectors</a>
                </td>
                <td>3</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E[foo*="bar"]</td>
                <td>an E element whose "foo" attribute value contains the substring "bar"</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#attribute-selectors">Attribute selectors</a>
                </td>
                <td>3</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E[foo|="en"]</td>
                <td>an E element whose "foo" attribute has a hyphen-separated list of values beginning (from the left) with "en"</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#attribute-selectors">Attribute selectors</a>
                </td>
                <td>2</td>
                <td>x</td>
                <td>x</td>
                <td>x</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E[attr operator value i]</td>
                <td>value compared case-insensitively (ASCII range).</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#attribute-selectors">Attribute selectors</a>
                </td>
                <td>4</td>
                <td>x</td>
                <td>x</td>
                <td>?</td>
                <td>
                    <a href="https://www.w3.org/TR/selectors-4/#attribute-case">i identifier</a>
                </td>
            </tr>
            <tr>
                <td>E[attr operator value s]</td>
                <td>value compared case-sensitively (ASCII range).</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#attribute-selectors">Attribute selectors</a>
                </td>
                <td>4</td>
                <td>x</td>
                <td>x</td>
                <td>x</td>
                <td>
                    <a href="https://www.w3.org/TR/selectors-4/#attribute-case">s identifier</a>
                </td>
            </tr>
            <tr>
                <td>E:root</td>
                <td>an E element, root of the document</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>HTML node only</td>
            </tr>
            <tr>
                <td>E:nth-child(n)</td>
                <td>an E element, the n-th child of its parent</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>nth-child(odd) and (even) as well as nth-child(range) also supported</td>
            </tr>
            <tr>
                <td>E:nth-last-child(n)</td>
                <td>an E element, the n-th child of its parent, counting from the last one</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:nth-of-type(n)</td>
                <td>an E element, the n-th sibling of its type</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:nth-last-of-type(n)</td>
                <td>an E element, the n-th sibling of its type, counting from the last one</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:first-child</td>
                <td>an E element, first child of its parent</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>2</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:last-child</td>
                <td>an E element, last child of its parent</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:first-of-type</td>
                <td>an E element, first sibling of its type</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:last-of-type</td>
                <td>an E element, last sibling of its type</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:only-child</td>
                <td>an E element, only child of its parent</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:only-of-type</td>
                <td>an E element, only sibling of its type</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:empty</td>
                <td>an E element that has no children (including text nodes)</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#structural-pseudos">Structural pseudo-classes</a>
                </td>
                <td>3</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:link</td>
                <td rowspan="2">an E element being the source anchor of a hyperlink of which the target is not yet visited (:link) or already visited (:visited)</td>
                <td rowspan="2">
                    <a href="https://drafts.csswg.org/selectors-3/#link">The link pseudo-classes</a>
                </td>
                <td>1</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:visited</td>
                <td>1</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E:not(s)</td>
                <td>an E element that does not match simple selector s</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#negation">Negation pseudo-class</a>
                </td>
                <td>3</td>
                <td>✔*</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E F</td>
                <td>an F element descendant of an E element</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#descendant-combinators">Descendant combinator</a>
                </td>
                <td>1</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E &gt; F</td>
                <td>an F element child of an E element</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#child-combinators">Child combinator</a>
                </td>
                <td>2</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E + F</td>
                <td>an F element immediately preceded by an E element</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#adjacent-sibling-combinators">Next-sibling combinator</a>
                </td>
                <td>2</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>E ~ F</td>
                <td>an F element preceded by an E element</td>
                <td>
                    <a href="https://drafts.csswg.org/selectors-3/#general-sibling-combinators">Subsequent-sibling combinator</a>
                </td>
                <td>3</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>foo, bar</td>
                <td>foo, bar&nbsp;will match both&nbsp;&lt;foo&gt;&nbsp;and&nbsp;&lt;bar&gt;&nbsp;elements.</td>
                <td>
                    <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Selector_list">Selector list</a>
                </td>
                <td>1</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td>element.querySelector</td>
                <td>Expanded element.querySelector</td>
                <td>
                    <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector">Element.querySelector</a>
                </td>
                <td>API</td>
                <td>✔</td>
                <td>✔</td>
                <td>✔</td>
                <td>Can now chain querySelector(All) calls on wider base node range</td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td>Lib info:</td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td>Microsoft HTML Object Library (MSHTML)</td>
                <td>MS Internet Explorer Controls (SHDocVw)</td>
                <td>Selenium Type Library (Chromedriver)</td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td>Lib</td>
                <td>mshtml.dll</td>
                <td>ieframe.dll</td>
                <td>selenium.dll</td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td>File Version</td>
                <td>11.00.19041.985</td>
                <td>11.0.19041.964</td>
                <td>2.0.9.0</td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td>Date</td>
                <td>2021-05-12</td>
                <td>2021-05-12</td>
                <td>2016-03-02</td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
        </table>
    </body>
    </html>

    12 个新支持的伪类和扩展的 Element.querySelector:

    如果你运行上面的 sn-p 并查看完整页面,你会看到现在至少有 12 个新支持的伪类被支持,并且提到了扩展的Element.querySelectorBam,kapow,ker-sploosh,关上众所周知的前门...欢迎来到 VBA CSS Canaan,Scraper 的香格里拉,Nerd Nirvana!

    我认为ieframe.dll 可能也有有趣的更新;这里的重点是最近的mshtml.dll 更改。您不妨查看 Lifecyle 公告herehere 下的 IE 支持,或搜索Lifecycle FAQ - Internet Explorer and Microsoft Edge

    由于扩展Element.querySelector()的好处在上一个问答中没有涉及,所以我在这里简单提一下。通过扩展,我的意思是增加了可以调用querySelector 的元素数量,这样您就可以链接.querySelector(),即.querySelector(..).querySelector(..).querySelector(..).querySelectorAll(..)

    以前,这在很大程度上是不可能的。如this 问题所示。通常,解决方法是将传统方法链接到返回的节点上,例如 html.querySelector("body").getElementsByTagName("li");这会导致难看的链接,难以遵循,以及目标元素的路径有限。恕我直言,更好的是代理MSHTML.HTMLDocument 变量的想法,它将携带querySelector 返回的当前节点的innerHTML,从而允许您再次调用querySelector(All);从而获得更快的匹配、更清晰的语法和更大的多功能性。这种方法的许多例子here


    尾注:

    这是一份正在修订的文件。欢迎所有关于改进的反馈。


    谢谢:

    最后,非常感谢 @SIM 运行我的测试脚本来检查不同的设置。

    【讨论】:

      猜你喜欢
      • 2012-12-24
      • 1970-01-01
      • 1970-01-01
      • 2011-03-29
      • 1970-01-01
      • 2014-07-04
      • 1970-01-01
      • 2015-05-02
      • 2011-01-22
      相关资源
      最近更新 更多