【问题标题】:Detect all images with Javascript in an html page在 html 页面中使用 Javascript 检测所有图像
【发布时间】:2019-02-25 22:13:26
【问题描述】:

我正在编写一个 chrome 扩展程序,我正在尝试检测网页中的所有图像。

我正在尝试在我的 JS 代码中检测网页上的所有图像,我的意思是:

  1. 网页加载后加载的图片
  2. 用作背景的图像(在 CSS 或内联 html 中)
  3. 可以在网页加载完成后加载的图片,例如,在进行 google 图片搜索时,很容易找到所有图片,但是一旦您单击一张图片将其放大,则无法检测到该图片。浏览社交媒体网站也是如此。

我现在拥有的代码可以很容易地找到初始图像 (1)。但我在其他两个部分 (2) 和 (3) 中挣扎。

这是我当前在 contentScript.js 中的代码:

var images = document.getElementsByTagName('img');
for (var i = 0, l = images.length; i < l; i++) {
    //Do something
}

我应该如何修改它,以便它实际上可以检测到所有其他图像(2 和 3)。

我在 SO 上看到了几个关于 (2) 的问题,例如 this onethis one,但似乎没有一个答案完全满足我的第二个要求,而且没有一个是关于第三个要求的。

【问题讨论】:

  • 关于第 3 点。您不能只执行 setInterval() 并检查 DOM 中是否有新图像吗?
  • @filip 似乎计算量很大(尤其是如果您希望立即检测到新图像,这是我的一项要求)。我在想更多的事情,比如捕捉事件。难道没有任何事件可以让我知道某些内容已添加到 DOM 中,然后只需检查其中包含的内容以查看是否有图像吗?
  • 找到了一个叫做 MutationObserver 的东西,它检查 DOM 中的变化(例如添加 标签)developer.mozilla.org/en-US/docs/Web/API/MutationObserver@LBes
  • 有趣的@filip 会在我下班回来时尝试一下

标签: javascript html css image google-chrome-extension


【解决方案1】:

即时图片集

正如@vsync 所说,查找所有HTML 图像就像var images = document.images 一样简单。这将是一个实时列表,因此从页面中动态添加或删除的任何图像都将自动反映在列表中。

提取背景图片(内联和 CSS)

有几种方法可以检查背景图像,但也许最可靠的方法是遍历所有页面元素并使用window.getComputedStyle 检查每个元素的backgroundImage 是否不等于none。这将获得内联和 CSS 设置的背景图像。

var images = [];
var elements = document.body.getElementsByTagName("*");
Array.prototype.forEach.call( elements, function ( el ) {
    var style = window.getComputedStyle( el, false );
    if ( style.backgroundImage != "none" ) {
        images.push( style.backgroundImage.slice( 4, -1 ).replace(/['"]/g, "")
    }
}

window.getComputedStyle 获取背景图像将返回完整的CSS background-image 属性,格式为url(...),因此您需要删除url()。您还需要删除 URL 周围的所有 "'。您可以使用 backgroundImage.slice( 4, -1 ).replace(/['"]/g, "")

来完成此操作

只有在 DOM 准备好后才开始检查,否则您的初始扫描可能会丢失元素。

动态添加的背景图片

这不会提供实时列表,因此您需要MutationObserver 来观看文档,并检查任何更改的元素是否存在backgroundImage

在配置观察者时,确保您的 MutationObserver 配置将 childListsubtree 设置为 true。这意味着它可以监视指定元素的所有子元素(在您的情况下为 body)。

var body = document.body;
var callback = function( mutationsList, observer ){
    for( var mutation of mutationsList ) {
        if ( mutation.type == 'childList' ) {
            // all changed children are in mutation.target.children
            // so iterate over them as in the code sample above
        }
    }
}
var observer = new MutationObserver( callback );
var config = { characterData: true,
            attributes: false,
            childList: true,
            subtree: true };
observer.observe( body, config );

由于搜索背景图片需要检查 DOM 中的每个元素,因此您不妨同时检查 &lt;img&gt;s,而不是使用 document.images

代码

您可能希望修改上面的代码,以便除了检查它是否有背景图像之外,还要检查它的标签名称是否为IMG。您还应该将它放在一个在 DOM 准备好时运行的函数中。

更新:为了区分图像和背景图像,您可以将它们推送到不同的数组,例如 imagesbg_images。要同时识别图像的父级,您可以将image.parentNode 推送到第三个数组,例如image_parents

var images = [],
    bg_images = [],
    image_parents = [];
document.addEventListener('DOMContentLoaded', function () {
    var body = document.body;
    var elements = document.body.getElementsByTagName("*");

    /* When the DOM is ready find all the images and background images
        initially loaded */
    Array.prototype.forEach.call( elements, function ( el ) {
        var style = window.getComputedStyle( el, false );
        if ( el.tagName === "IMG" ) {
            images.push( el.src ); // save image src
            image_parents.push( el.parentNode ); // save image parent

        } else if ( style.backgroundImage != "none" ) {
            bg_images.push( style.backgroundImage.slice( 4, -1 ).replace(/['"]/g, "") // save background image url
        }
    }

    /* MutationObserver callback to add images when the body changes */
    var callback = function( mutationsList, observer ){
        for( var mutation of mutationsList ) {
            if ( mutation.type == 'childList' ) {
                Array.prototype.forEach.call( mutation.target.children, function ( child ) {
                    var style = child.currentStyle || window.getComputedStyle(child, false);
                    if ( child.tagName === "IMG" ) {
                        images.push( child.src ); // save image src
                        image_parents.push( child.parentNode ); // save image parent
                    } else if ( style.backgroundImage != "none" ) {
                        bg_images.push( style.backgroundImage.slice( 4, -1 ).replace(/['"]/g, "") // save background image url
                    }
                } );
            }
        }
    }
    var observer = new MutationObserver( callback );
    var config = { characterData: true,
                attributes: false,
                childList: true,
                subtree: true };

    observer.observe( body, config );
});

【讨论】:

  • 您的答案的第一部分指出“var iamges = document.images。这将是一个实时列表,因此从页面中动态添加或删除的任何图像都将自动反映在列表中。 "我已经有了,它在新加载的内容上根本不起作用(参见点击谷歌图片上的图片,或在社交媒体上滚动)
  • @LBes 很有趣,规范表明它应该是一个实时集合。 document.images 是一个相当古老的标准,HTML 规范建议将 getElementsByTagName("img") 作为另一种选择。然而,使用MutationObserver 解决方案并检查IMG 标签名称的更改元素以及背景图像可能是最强大和最完整的解决方案。
  • 这是第二个答案的建议,但请在那里查看我的 cmets。
  • @LBes 错误is not of type 'Node' 意味着当您的代码运行时,您附加观察者的元素不存在。正如我的回答中所建议的那样,使用document.addEventListener('DOMContentLoaded', function () { 等待DOM 加载;如果元素在 DOM 之后加载,请参阅 stackoverflow.com/questions/40398054/… 以获取轮询直到元素准备就绪的解决方案。
  • 感谢您的更新。是的,它被正确设置为 true ......我也不明白为什么它不起作用。无论如何接受答案,因为这是一个非常具体的案例,但我仍然想弄清楚。如果您有想法,请随时以我的方式发送:)
【解决方案2】:

对于 HTML 图像(运行时已经存在):

document.images

对于 CSS 图像:

您可能需要在页面的 CSS(内联文件或外部文件)上使用 REGEX,但这很棘手,因为您需要从相对路径中动态构建完整路径,而这可能并不总是有效。

Getting all css used in html file


对于延迟加载的图片:

您可以使用突变观察者,就像@filip 在他的回答中建议的那样

【讨论】:

  • 好的,感谢您的指点。 +1。我担心它并不总是有效。
【解决方案3】:

这应该可以解决您的 3. 问题。我用了MutationObserver

我会检查targetNode 的更改并添加回调,如果发生更改。

对于您的情况,targetNode 应该是检查整个文档更改的根元素。

在回调中,我询问突变是否添加了带有“IMG”标签的节点。

    const targetNode = document.getElementById("root");

    // Options for the observer (which mutations to observe)
    let config = { attributes: true, childList: true, subtree: true };

    // Callback function to execute when mutations are observed
    const callback = function(mutationsList, observer) {
        for(let mutation of mutationsList) {
            if (mutation.addedNodes[0].tagName==="IMG") {
                console.log("New Image added in DOM!");
            }   
        }
    };

    // Create an observer instance linked to the callback function
    const observer = new MutationObserver(callback);

    // Start observing the target node for configured mutations
    observer.observe(targetNode, config);

【讨论】:

  • 好吧似乎是要走的路。点赞!但我得到一个“无法在'MutationObserver'上执行'observe':参数1不是'Node'类型。”在线observer.observe(targetNode, config);
  • @LBes 你将 targetNode 变量设置为什么?你不能只使用 document.body 或类似的东西。我为 标签定义了一个 id,然后通过 document.getElementByID("root"); 得到它
  • 我确实使用了 document.body。但是你建议使用什么,不知道我明白你的意思
  • @LBes HTML: .... JS: targetNode = document.getElementById("root");
  • 这对我不起作用。这是一个 chrome 扩展,它必须在每个页面上工作:s
猜你喜欢
  • 2011-05-14
  • 1970-01-01
  • 1970-01-01
  • 2014-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-07
  • 1970-01-01
相关资源
最近更新 更多