Last active
November 2, 2024 17:54
-
-
Save bryant988/9510cff838d86dcefa3b9ea3835b8552 to your computer and use it in GitHub Desktop.
Zillow Image Downloader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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); |
I haven't been able to get the above solutions to work but I was able to use @hzarrabi's snippet as a base for this script. Theirs should be more reliable but for some reason only a small number of the actual images were ever found in the resources... I expect this to be fairly brittle given it's relying on data attributes to select DOM elements but as of now (November 2, 2024) it works a treat. I threw in some options at the top for image format and sizes Zillow makes available as well.
const TARGET_FORMAT = "jpeg"; // Options: `jpeg` or `webp`
const TARGET_SIZE = "1536"; // Options: `1536`, `1344`, `1152`, `960`, `768`, `576`, `384`, `192`
// Load JSZip library
const script = document.createElement('script');
script.src = "https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js";
document.head.appendChild(script);
script.onload = function() {
// Function to download the zip file
function downloadZip(zip) {
zip.generateAsync({type: 'blob'}).then(function(content) {
const link = document.createElement('a');
link.href = URL.createObjectURL(content);
link.download = 'images.zip';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
}
// Function to gather and zip image URLs from "media wall"
function gatherAndZipImages() {
// Gather the image URLs
const mediaWall = document.querySelector('ul[data-cy="hollywood-vertical-media-wall"]');
const sources = Array.from(mediaWall.querySelectorAll(`source[type="image/${TARGET_FORMAT}"]`));
// Try to pull the largest src URL from a source's srcset
// srcset is in the format "<url> <size>, <url> <size>" so we split it and try to grab the last (hopefully largest) URL
// It shouldn't really matter, though, since the regex will replace the target size with the largest possible anyway
const imageUrls = sources.map(source => {debugger; return source.srcset.split(",").at(-1).split(" ")[1].replaceAll(/_\d+.(jpg|webp)/g, `_${TARGET_SIZE}.${TARGET_FORMAT}`)});
const zip = new JSZip();
const imgFolder = zip.folder("images");
if (imageUrls.length > 0) {
console.log('Image URLs:', imageUrls);
const downloadPromises = imageUrls.map((url, index) => {
return fetch(url).then(response => response.blob()).then(blob => {
imgFolder.file(`image_${index + 1}.${TARGET_FORMAT}`, blob);
});
});
Promise.all(downloadPromises).then(() => {
downloadZip(zip);
});
} else {
console.log(`No .${TARGET_FORMAT} images found.`);
}
}
// Execute the function to gather and zip images
gatherAndZipImages();
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This also worked for me. So long as you scroll down in the Zillow image gallery to get all the images it will gather all the images in a zip folder for you. I targeted all the .webp images since that's the image type that Zillow requests/uses.