/** | |
* NOTE: this specifically works if the house is for sale since it renders differently. | |
* This will download the highest resolution available per image. | |
*/ | |
/** | |
* STEP 1: Make sure to *SCROLL* through all images so they appear on DOM. | |
* No need to click any images. | |
*/ | |
/** | |
* STEP 2: Open Dev Tools Console. | |
* Copy and paste code below | |
*/ | |
const script = document.createElement('script'); | |
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"; | |
script.onload = () => { | |
$ = jQuery.noConflict(); | |
const imageList = $('ul.media-stream li picture source[type="image/jpeg"]').map(function () { | |
const srcset = $(this).attr('srcset').split(' '); // get highest res urls for each image | |
return srcset[srcset.length - 2] | |
}).toArray(); | |
const delay = ms => new Promise(res => setTimeout(res, ms)); // promise delay | |
// get all image blobs in parallel first before downloading for proper batching | |
Promise.all(imageList.map(i => fetch(i)) | |
).then(responses => | |
Promise.all(responses.map(res => res.blob())) | |
).then(async (blobs) => { | |
for (let i = 0; i < blobs.length; i++) { | |
if (i % 10 === 0) { | |
console.log('1 sec delay...'); | |
await delay(1000); | |
} | |
var a = document.createElement('a'); | |
a.style = "display: none"; | |
console.log(i); | |
var url = window.URL.createObjectURL(blobs[i]); | |
a.href = url; | |
a.download = i + ''; | |
document.body.appendChild(a); | |
a.click(); | |
setTimeout(() => { | |
window.URL.revokeObjectURL(url); | |
}, 100); | |
} | |
}); | |
}; | |
document.getElementsByTagName('head')[0].appendChild(script); |
amolshambharkar
commented
Aug 12, 2021
via email
@TheSharpieOne
Your code is off by one at the end. The final image has a reload icon instead of a next one, and it doesn't get downloaded. This works for me:// can't map since there isn't a list, so just push as we find more. const imageList = []; // while there is a next button while($('div.zsg-icon-expando-right').length || $('div.zsg-icon-reload').length) { const srcs = $('.hdp-photo-gallery-lightbox-content .hdp-gallery-image-content:visible source[type="image/jpeg"]').attr('srcset').split(' '); const src = srcs[srcs.length - 2]; // just in case... let make sure the src is not already in the list. if (imageList.indexOf(src) === -1) { imageList.push(src); } // Last image, break out of loop if ($('div.zsg-icon-reload').length) { break; } // go to the next slide $('div.zsg-icon-expando-right').click(); }Thanks for the help, for some reason I only got 6 downloaded before modifying the source to this code. Thanks everyone for your contribution!
I noticed that you have to vertically scroll through all of the photos before running the script. After that, click on one of the photos to enter the view modal. After that you'll see the forward and back arrows appear. Once you see the forward and back arrows, run the script.
When I used this on closed listings it worked, but on open listing the last slide regarding request a showing would cause the entire script to error out. I had to remove || $('div.zsg-icon-reload'
for the open listing.
the code @beppodb posted worked for me today on a closed home
For the full resolution images, they use the same base url as the srcset ones so you can just call .replace(/cc_ft_384.jpg|cc_ft_576.jpg/, 'uncropped_scaled_within_1536_1152.jpg')
to find the urls of the full res images for download. My quick and dirty modification is here but I don't know if it generalizes to all possible resolutions.
const script = document.createElement('script');
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js";
script.onload = () => {
$ = jQuery.noConflict();
const imageList = $('ul.media-stream li picture source[type="image/jpeg"]').map(function () {
const srcset = $(this).attr('srcset').split(' '); // get highest res urls for each image
console.log(srcset);
return srcset[srcset.length - 2].replace(/cc_ft_384.jpg|cc_ft_576.jpg/, 'uncropped_scaled_within_1536_1152.jpg')
}).toArray();
console.log(imageList);
const delay = ms => new Promise(res => setTimeout(res, ms)); // promise delay
// get all image blobs in parallel first before downloading for proper batching
Promise.all(imageList.map(i => fetch(i))
).then(responses =>
Promise.all(responses.map(res => res.blob()))
).then(async (blobs) => {
for (let i = 0; i < blobs.length; i++) {
if (i % 10 === 0) {
console.log('1 sec delay...');
await delay(1000);
}
var a = document.createElement('a');
a.style = "display: none";
console.log(i);
var url = window.URL.createObjectURL(blobs[i]);
a.href = url;
a.download = i + '';
document.body.appendChild(a);
a.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
}, 100);
}
});
};
document.getElementsByTagName('head')[0].appendChild(script);
Thanks for looking into it @ziyiwu9494! Strangely this worked only for the first 6 images only. This is the listing I'm looking at.
@imageEngineer I just changed it to match any initial resolution and it seems to work now. Try this:
const script = document.createElement('script');
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js";
script.onload = () => {
$ = jQuery.noConflict();
const imageList = $('ul.media-stream li picture source[type="image/jpeg"]').map(function () {
const srcset = $(this).attr('srcset').split(' '); // get highest res urls for each image
return srcset[srcset.length - 2].replace(/cc_ft_.*.jpg/, 'uncropped_scaled_within_1536_1152.jpg')
}).toArray();
const delay = ms => new Promise(res => setTimeout(res, ms)); // promise delay
// get all image blobs in parallel first before downloading for proper batching
Promise.all(imageList.map(i => fetch(i))
).then(responses =>
Promise.all(responses.map(res => res.blob()))
).then(async (blobs) => {
for (let i = 0; i < blobs.length; i++) {
if (i % 10 === 0) {
console.log('1 sec delay...');
await delay(1000);
}
var a = document.createElement('a');
a.style = "display: none";
console.log(i);
var url = window.URL.createObjectURL(blobs[i]);
a.href = url;
a.download = i + '';
document.body.appendChild(a);
a.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
}, 100);
}
});
};
document.getElementsByTagName('head')[0].appendChild(script);
For some reason it's still only getting the first 6 images for me @ziyiwu9494. Not sure why.
@imageEngineer Have you made sure to scroll through and load all the images before trying to download?
@ziyiwu9494 yeah. I load the page, open the gallery, flip through all the images, return to the first image and run the script.
@imageEngineer You don't need to go through the gallery, you just need to scroll through the images on the page itself.
Just used @beppodb 's code on my home that closed a while back, but pix were still up - perfect! Thanks a ton!
@ziyiwu9494's code worked great!
It worked fine for me today:
How to execute it :
- Open the listing photos you need to download on website (I used google chrome browser) and it should look like this
- Then right click and select inspect it would look like this :
- then select console and paste the code provided by @beppodb or @ziyiwu9494 (tested both and worked just fine) and hit enter.
it will then ask you to save on ur computer by using a pop up for every file. Keep hitting enter and it will stop producing more pop ups once all phots have been downloaded.
In last if you are still having issues, please let me know I'll be happy to help to use this utility
Thanks to @bryant988 and all other contributors. Good job!
Only Firefox worked for me running code last posted by ziyiwu9494 (https://gist.github.com/bryant988/9510cff838d86dcefa3b9ea3835b8552?permalink_comment_id=4016913#gistcomment-4016913). However, I got only 12/99 photos every time. Increasing the delay to 2 seconds worked like a charm. Updated code with the 2 second delay below.
Also, I flipped through all the images from the gallery first, and then ran the code in the console (righ-click > Inspect) from the first image.
const script = document.createElement('script');
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js";
script.onload = () => {
$ = jQuery.noConflict();
const imageList = $('ul.media-stream li picture source[type="image/jpeg"]').map(function () {
const srcset = $(this).attr('srcset').split(' '); // get highest res urls for each image
return srcset[srcset.length - 2].replace(/cc_ft_.*.jpg/, 'uncropped_scaled_within_1536_1152.jpg')
}).toArray();
const delay = ms => new Promise(res => setTimeout(res, ms)); // promise delay
// get all image blobs in parallel first before downloading for proper batching
Promise.all(imageList.map(i => fetch(i))
).then(responses =>
Promise.all(responses.map(res => res.blob()))
).then(async (blobs) => {
for (let i = 0; i < blobs.length; i++) {
if (i % 10 === 0) {
console.log('2 sec delay...');
await delay(2000);
}
var a = document.createElement('a');
a.style = "display: none";
console.log(i);
var url = window.URL.createObjectURL(blobs[i]);
a.href = url;
a.download = i + '';
document.body.appendChild(a);
a.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
}, 100);
}
});
};
document.getElementsByTagName('head')[0].appendChild(script);
I kept getting 6 photos only so I had to change
$('ul.media-stream li picture source[type="image/jpeg"]').map(function () {
to
$('picture source[type="image/jpeg"]').map(function () {
Same issue, 6 photos only but your mod gives me an error,
Uncaught TypeError: Cannot read properties of undefined (reading 'replace')
at HTMLSourceElement. (:9:38)
at VM1211 jquery.min.js:2:935
at Function.map (VM1211 jquery.min.js:2:3485)
at n.fn.init.map (VM1211 jquery.min.js:2:903)
at HTMLScriptElement.script.onload (:7:64)
I kept getting 6 photos only so I had to change
$('ul.media-stream li picture source[type="image/jpeg"]').map(function () {
to
$('picture source[type="image/jpeg"]').map(function () {
@joncl Worked perfectly for me, thank you! Scrolled so all the thumbnails loaded into the DOM and pasted this in. Firefox v100.0.
@joncl's version worked as expected for me. Thanks!
Hi. Can I pay someone to help me with this? I have one listing on Zillow. TIA
@teriross - are you having any issues? Here are the steps:
- Open the listing in Firefox or Google Chrome
- Click on the first image, then click through each image so they are loaded to your browser
- Right click anywhere on the page and select "Inspect"
- Click on the "console" tab of the window that just opened
- If on firefox, first type allow pasting and press enter
- Paste this code and click enter (this is @joncl's code with @methodin's fix added):
const script = document.createElement('script');
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js";
script.onload = () => {
$ = jQuery.noConflict();
const imageList = $('picture source[type="image/jpeg"]').map(function () {
const srcset = $(this).attr('srcset').split(' '); // get highest res urls for each image
return srcset[srcset.length - 2].replace(/cc_ft_.*.jpg/, 'uncropped_scaled_within_1536_1152.jpg')
}).toArray();
const delay = ms => new Promise(res => setTimeout(res, ms)); // promise delay
// get all image blobs in parallel first before downloading for proper batching
Promise.all(imageList.map(i => fetch(i))
).then(responses =>
Promise.all(responses.map(res => res.blob()))
).then(async (blobs) => {
for (let i = 0; i < blobs.length; i++) {
if (i % 10 === 0) {
console.log('2 sec delay...');
await delay(2000);
}
var a = document.createElement('a');
a.style = "display: none";
console.log(i);
var url = window.URL.createObjectURL(blobs[i]);
a.href = url;
a.download = i + '';
document.body.appendChild(a);
a.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
}, 100);
}
});
};
document.getElementsByTagName('head')[0].appendChild(script);
You should get a download prompt for each image if using Chrome, and if using Firefox the download center will open and show each image being downloaded.
If this works for you, then I'll take payment in the form of a donation of any amount to https://www.climatefoundation.org/ :)
TY! Still working as of today, using bxs1260 instructions. Great for cataloging favorite ZIllow listings/photos every now and then.
TY again, to all contributors!
Thanks for the code and all the comments so far. Here are some additional insights:
- Code runs based on Zillow picture tiles when you click on the property. Scroll all the way down to load all the squares in the tiles, especially listings with over 10 pictures. Otherwise only 8 or so pics would be downloaded.
- Zillow has changed the download function so only low resolution JFIF files would be downloaded by the browser.
- I made a change to the code to download WEBP files (uncropped_scaled_within_1536_1152.webp)
- You can convert WEBP files to JPG online using https://anywebp.com/ (20 pics at a time). Scale your JPG to 2x for converting and download HiRes pics
- Here's the update code that I used:
const script = document.createElement('script');
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js";
script.onload = () => {
$ = jQuery.noConflict();
const imageList = $('ul.media-stream li picture source[type="image/jpeg"]').map(function () {
const srcset = $(this).attr('srcset').split(' '); // get highest res urls for each image
return srcset[srcset.length - 2].replace(/cc_ft_.*.jpg/, 'uncropped_scaled_within_1536_1152.webp')
}).toArray();
const delay = ms => new Promise(res => setTimeout(res, ms)); // promise delay
Promise.all(imageList.map(i => fetch(i))
).then(responses =>
Promise.all(responses.map(res => res.blob()))
).then(async (blobs) => {
for (let i = 0; i < blobs.length; i++) {
if (i % 10 === 0) {
console.log('1 sec delay...');
await delay(1000);
}
var a = document.createElement('a');
a.style = "display: none";
console.log(i);
var url = window.URL.createObjectURL(blobs[i]);
a.href = url;
a.download = i + '';
document.body.appendChild(a);
a.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
}, 100);
}
});
};
document.getElementsByTagName('head')[0].appendChild(script);
Thanks @raghucbz I can confirm your version works as of April 2023.
Working in May as well. Thank you @raghucbz !
Hi everyone!!
Thanks for the great information!! I was able to get the code to work on Zillow. Does anyone know of a similar code to work on Redfin?