-
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.
| /** | |
| * 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); |
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;
try {
const url = new URL(raw, location.href);
url.search = "";
if (!url.hostname.endsWith("zillowstatic.com")) return null;
if (!url.pathname.includes("/fp/")) return null;
if (!/\.(jpe?g|webp)$/i.test(url.pathname)) return null;
return url.href;
} catch {
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();
const numbers = [...path.matchAll(/[_-](\d{3,4})(?=[_.-]|\.(?:jpe?g|webp)$)/g)]
.map(match => Number(match[1]));
const maxSize = numbers.length ? Math.max(...numbers) : 0;
const jpgBonus = /\.(jpg|jpeg)$/i.test(path) ? 25 : 0;
return maxSize * 100 + jpgBonus;
}
function add(raw) {
const url = cleanUrl(raw);
if (!url) return;
const key = photoKey(url);
const existing = found.get(key);
if (!existing || qualityScore(url) > qualityScore(existing)) {
found.set(key, url);
}
}
function addSrcset(srcset) {
if (!srcset) return;
srcset.split(",").forEach(part => {
const url = part.trim().split(/\s+/)[0];
add(url);
});
}
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);
})();
@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
Excellent! Worked perfectly May 2026!