Last active
May 22, 2026 15:46
-
Star
(159)
You must be signed in to star a gist -
Fork
(20)
You must be signed in to fork a gist
-
-
Save bryant988/9510cff838d86dcefa3b9ea3835b8552 to your computer and use it in GitHub Desktop.
Zillow Image Downloader
This file contains hidden or 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); |
@McMilez :(
Uncaught SyntaxError: expected expression, got '}'
debugger eval code:1
eval-with-debugger.js:304:22
getEvalResult resource://devtools/server/actors/webconsole/eval-with-debugger.js:304
evalWithDebugger resource://devtools/server/actors/webconsole/eval-with-debugger.js:218
evaluateJS resource://devtools/server/actors/webconsole.js:896
evaluateJSAsync resource://devtools/server/actors/webconsole.js:789
makeInfallible resource://devtools/shared/ThreadSafeDevToolsUtils.js:103
enter resource://devtools/server/actors/utils/event-loop.js:82
_pauseAndRespond resource://devtools/server/actors/thread.js:984
onDebuggerStatement resource://devtools/server/actors/thread.js:1970
debugger eval code:1
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated script here:
(() => {
const SCRIPT_NAME = "download-zillow-images.sh";
const FOLDER_NAME = "zillow-images";
const ZIP_NAME = "zillow-images.zip";
const found = new Map();
function cleanUrl(raw) {
if (!raw) return null;
}
function photoKey(url) {
const path = new URL(url).pathname;
return path.match(//fp/([^-./]+)/)?.[1] || path;
}
function qualityScore(url) {
const path = new URL(url).pathname.toLowerCase();
}
function add(raw) {
const url = cleanUrl(raw);
if (!url) return;
}
function addSrcset(srcset) {
if (!srcset) return;
}
document.querySelectorAll("img, source").forEach(el => {
add(el.currentSrc);
add(el.src);
addSrcset(el.srcset);
});
performance.getEntriesByType("resource").forEach(entry => {
add(entry.name);
});
const html = document.documentElement.innerHTML
.replaceAll("\u002F", "/")
.replaceAll("\/", "/")
.replaceAll("&", "&");
const urlRegex = /https?://photos.zillowstatic.com/fp/[^\s"'<>\\]+?.(?:jpe?g|webp)/gi;
for (const match of html.matchAll(urlRegex)) {
add(match[0]);
}
const urls = [...found.values()];
if (!urls.length) {
console.log("No Zillow photo URLs found. Open the full photo gallery, scroll through the photos, then run this again.");
return;
}
const script = `#!/usr/bin/env bash
set -euo pipefail
mkdir -p "${FOLDER_NAME}"
cat > zillow-image-urls.txt <<'URLS'
${urls.join("\n")}
URLS
i=1
while IFS= read -r url; do
clean="${url%%\?}"
ext="${clean##.}"
case "$ext" in
jpg|jpeg|webp) ;;
*) ext="jpg" ;;
esac
out=$(printf "${FOLDER_NAME}/image_%03d.%s" "$i" "$ext")
echo "Downloading $out"
curl -L --fail --retry 3 --connect-timeout 20 \
-A "Mozilla/5.0" \
-e "${location.href}" \
"$url" \
-o "$out"
i=$((i + 1))
done < zillow-image-urls.txt
zip -qr "${ZIP_NAME}" "${FOLDER_NAME}"
echo "Done: ${ZIP_NAME}"
`;
const blobUrl = URL.createObjectURL(
new Blob([script], { type: "text/x-shellscript" })
);
const link = document.createElement("a");
link.href = blobUrl;
link.download = SCRIPT_NAME;
document.body.appendChild(link);
link.click();
link.remove();
setTimeout(() => URL.revokeObjectURL(blobUrl), 5000);
console.log(
Found ${urls.length} photos.);console.log(
Downloaded ${SCRIPT_NAME}.);console.log("Then run this in Terminal:");
console.log(
cd ~/Downloads && bash ${SCRIPT_NAME});console.log("Photo URLs:", urls);
})();