Download multiple images at once with Javascript
Asked Answered
B

4

9

I'm attempting to download multiple images at once using javascript in a chrome extension. I'd like to do this by firing clicks on each of the images (each wrapped in an href tag with a download attribute, and the class "clickit"). The idea is to loop through each href with the clickit class and fire a mouse click, thus downloading the image.

The following code downloads only the first of n = 25 images, but is called 25 times (console logs "got here" that many times).

var evt = document.createEvent("MouseEvents");

evt.initMouseEvent("click", true, true, window,
        0, 0, 0, 0, 0, false, false, false, false, 0, null);

[].forEach.call( document.getElementsByClassName("clickit"), function(elem){
  console.log("got here");
  elem.dispatchEvent(evt);
});

I've tried an alternate method, but this code almost immediately crashes chrome (throwing KERN_PROTECTION_FAILURE's in the logs):

for (var i = 0; i < document.getElementsByClassName("clickit").length; i++){  
    var clickEvent = document.createEvent("MouseEvents");
    clickEvent.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); 
    document.getElementsByClassName("clickit")[i].dispatchEvent(clickEvent);
}

In both cases, I have a feeling that I'm using the dispatchEvent() function incorrectly, but I cannot put my finger on it. In the first case, the retrieval of a single image properly is encouraging. I have a feeling I'm falling into bad memory access territory with the second case.

Any ideas?

Bosco answered 7/11, 2013 at 7:20 Comment(2)
you're hitting the browser with 25 simultaneous events in the UI thread. It might just be Chrome saying wtf!!!. Try wrapping the dispatchEvent in a setTimeout to give Chrome a chance.Disband
There are also client-side libraries to ZIP images such as JSZip. Not exactly what was asked for, but often likely the better experience for the user since only file will be downloaded.Lepidopteran
U
28

I don't know what the problem with your code might be (maybe the fact that document.createEvent() has been deprecated), but I was able to donwload some 90 imgs without chrome complaining about it at all (it may ask you once if you allow the webpage to download multiple images, but that's it).
Sample code:

/* Download an img */
function download(img) {
    var link = document.createElement("a");
    link.href = img.src;
    link.download = true;
    link.style.display = "none";
    var evt = new MouseEvent("click", {
        "view": window,
        "bubbles": true,
        "cancelable": true
    });

    document.body.appendChild(link);
    link.dispatchEvent(evt);
    document.body.removeChild(link);
    console.log("Downloading...");
}

/* Download all images in 'imgs'. 
 * Optionaly filter them by extension (e.g. "jpg") and/or 
 * download the 'limit' first only  */
function downloadAll(imgs, ext, limit) {
    /* If specified, filter images by extension */
    if (ext) {
        ext = "." + ext;
        imgs = [].slice.call(imgs).filter(function(img) {
            var src = img.src;
            return (src && (src.indexOf(ext, src.length - ext.length) !== -1));
        });
    }

    /* Determine the number of images to download */
    limit = (limit && (0 <= limit) && (limit <= imgs.length))
            ? limit : imgs.length;

    /* (Try to) download the images */
    for (var i = 0; i < limit; i++) {
        var img = imgs[i];
        console.log("IMG: " + img.src + " (", img, ")");
        download(img);
    }
}

As a demonstration, you can go to this FreeImages.co.uk Gallery, open the console and paste the above code, along with the following:

/* Callback for button's "click" event */
function doit() {
    var imgs = document.querySelectorAll("img");
    downloadAll(imgs, "jpg", -1);
}

/* Create and add a "download" button on the top, left corner */
function addDownloadBtn() {
    var btn = document.createElement("button");
    btn.innerText = "Download all images";
    btn.addEventListener("click", doit);
    btn.style.position = "fixed";
    btn.style.top = btn.style.left = "0px";
    document.body.appendChild(btn);
}
addDownloadBtn();

Then, by clicking the button that appears on the top, left, you'll get yourself a whole bunch of images :)
(NOTE: Your download folder will get filled with 90 images. Modify the "limit" parameter of downloadAll() to limit them if you wish.)

Uncounted answered 7/11, 2013 at 9:2 Comment(5)
I've modified your code a bit to fit into a content-script and everything works quite nicely. Thank you very much for your help!Bosco
Nooo ! You modified it ? Didn't you notice the Copyright notice ? Oh, I must have left that out while copy/pasting :/ Nevermind... Always glad to help :PUncounted
Doesn't work in firefox though! version - Mac 45.1.1 It just opens up the last image on the page. Any workaround?Pinxit
its not working for me in chrome , downloading the last image. Dunno what I am missingInstancy
I'm having trouble making this work, it will just open one of the images.Lenny
P
5

You don't need a chrome extension you could runt this in console or make a bookmarklet:

images=document.querySelectorAll("img"); for (i of images) { var a = document.createElement('a'); a.href = i.src; console.log(i); a.download = i.src; document.body.appendChild(a); a.click(); document.body.removeChild(a);}

same thing beautified for reading:

images = document.querySelectorAll("img");
for (i of images) {
    var a = document.createElement('a');
    a.href = i.src;
    console.log(i);
    a.download = i.src;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
}
Preconceive answered 15/2, 2018 at 22:56 Comment(0)
W
3

Eduard's answer wouldn't work for me using either Chrome, Firefox or Safari until I wrapped it in a setInterval(). An interval of 500 worked for me. Less may work but I figured allow a safety margin. Although I can see how that could add up if the image count is high.

var i = 0;

var id = setInterval( function() {

    if ( i >= images.length ) {
       clearInterval( id );
       return;
    }

   var image = images[i++];
   i++;
   var a = document.createElement('a');
   console.log( image )
   a.href = image.src
   a.download = image.src
   document.body.appendChild(a);
   a.click();
   document.body.removeChild(a);

}
Wally answered 16/6, 2018 at 12:43 Comment(1)
Maybe there is a kind of limit on how many images it can download. Thanks for improving and offering an alternative, upvotedPreconceive
S
2

If you need to download bulk images then you can use below script. Use this script in your developer tool from same website where you want to download images.

For example, if you need to download images from https://testing-images.com/images-1.jpg to https://testing-images/images-34.jpg Then go to https://testing-images.com website and open developer tools and go to console and run below script.

for(let i=1; i<35; i++){
  setTimeout(() => {
    fetch(`https://testing-images/images-${i}.jpg`)
      .then(resp => resp.blob())
      .then(blob => {
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.style.display = 'none';
        a.href = url;
        // the filename you want
        a.download = `slide-mian-${i}.jpg`;
        document.body.appendChild(a);
        a.click();
        window.URL.revokeObjectURL(url);
      })
      .catch(() => alert('oh no!'));
  }, i*1000);
}
Szeged answered 13/10, 2021 at 3:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.