【问题标题】:Can Xpath expressions access shadow-root elements?Xpath 表达式可以访问 shadow-root 元素吗?
【发布时间】:2018-09-20 15:55:00
【问题描述】:

目前我正在抓取文章新闻网站,在获取其主要内容的过程中,我遇到了很多在其中嵌入了这样的推文的问题:

我使用带有XPath helper(chrome addon) 的XPath 表达式来测试我是否可以获取内容,然后将此表达式添加到scrapy python,但是#shadow-root 中的元素似乎超出了范围对于 DOM,我正在寻找一种在这些类型的元素中获取内容的方法,最好是使用 XPath。

【问题讨论】:

    标签: xpath web-scraping scrapy shadow-dom


    【解决方案1】:

    使用不适用于 shadow DOM API 的工具抓取包含 shadow DOM 的页面的一种方法是递归迭代 shadow DOM 元素并用其 HTML 代码替换它们:

    // Returns HTML of given shadow DOM.
    const getShadowDomHtml = (shadowRoot) => {
        let shadowHTML = '';
        for (let el of shadowRoot.childNodes) {
            shadowHTML += el.nodeValue || el.outerHTML;
        }
        return shadowHTML;
    };
    
    // Recursively replaces shadow DOMs with their HTML.
    const replaceShadowDomsWithHtml = (rootElement) => {
        for (let el of rootElement.querySelectorAll('*')) {
            if (el.shadowRoot) {
                replaceShadowDomsWithHtml(el.shadowRoot)
                el.innerHTML += getShadowDomHtml(el.shadowRoot);
            }
        }
    };
    
    replaceShadowDomsWithHtml(document.body);
    

    如果您使用完整的浏览器(带有 Puppeteer、PhantomJS 等的 Chrome)进行抓取,那么只需将此脚本注入页面即可。重要的是在整个页面渲染后执行,因为它可能会破坏 shadow DOM 组件的 JS 代码。

    查看我写的关于这个主题的完整文章:https://kb.apify.com/tips-and-tricks/how-to-scrape-pages-with-shadow-dom

    【讨论】:

    • replaceShadowDomsWithHtml(shadowRoot); 应该是 replaceShadowDomsWithHtml(el.shadowRoot); 否则代码将抛出 Uncaught ReferenceError: shadowRoot is not defined
    【解决方案2】:

    大多数网络爬虫,包括 Scrapy,都不支持 Shadow DOM,因此您根本无法访问影子树中的元素。

    即使网络爬虫确实支持 Shadow DOM,但根本不支持 XPath。仅在某种程度上支持选择器,如 CSS Scoping spec 中所述。

    【讨论】:

    • 您是否知道不支持 shadow DOM 是否有特殊原因?据我所知,即使在scrapy shell 上调用 view(response) 时,它们也会得到渲染,我将其作为响应的一部分?
    猜你喜欢
    • 2018-05-11
    • 2021-02-06
    • 2019-06-14
    • 2019-12-13
    • 2014-10-02
    • 2021-01-04
    • 2021-03-31
    • 1970-01-01
    • 2013-05-14
    相关资源
    最近更新 更多