Last active
August 18, 2025 20:09
-
-
Save adnjoo/0ab41be4dfec4f14bb7ee74ebce458f4 to your computer and use it in GitHub Desktop.
Zillow Scrape Images
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
| /** | |
| * Zillow Image Scraper with ZIP Download | |
| * | |
| * - Collects all high-res JPG images from Zillow listing photo gallery | |
| * - Dedupes by photo ID (keeps largest resolution) | |
| * - Names ZIP file after the property address | |
| * - Uses JSZip + FileSaver loaded dynamically | |
| * | |
| * Usage: | |
| * 1. Open any Zillow listing in your browser | |
| * 2. Open DevTools Console | |
| * 3. Paste this script and hit Enter | |
| * 4. Wait a few seconds — a ZIP named <address>.zip will download | |
| */ | |
| (async function () { | |
| // Helper: dynamically load a script into <head> | |
| function loadScript(src) { | |
| return new Promise((resolve, reject) => { | |
| const script = document.createElement("script"); | |
| script.src = src; | |
| script.onload = resolve; | |
| script.onerror = reject; | |
| document.head.appendChild(script); | |
| }); | |
| } | |
| // Load JSZip and FileSaver safely | |
| if (typeof JSZip === "undefined") { | |
| await loadScript("https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"); | |
| } | |
| if (typeof saveAs === "undefined") { | |
| await loadScript("https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"); | |
| } | |
| // Try to get address for ZIP filename | |
| let address = "zillow-images"; | |
| const addressEl = document.querySelector("h1"); | |
| if (addressEl && addressEl.innerText.trim()) { | |
| address = addressEl.innerText.trim() | |
| .replace(/[^\w\d]+/g, "_") // replace spaces/punctuation with underscores | |
| .replace(/_+/g, "_") // collapse multiple underscores | |
| .replace(/^_|_$/g, ""); // trim underscores | |
| } | |
| // Locate the Zillow media wall | |
| const mediaWall = document.querySelector('ul[aria-label="media wall images"]'); | |
| if (!mediaWall) { | |
| console.log("❌ Could not find Zillow media wall on this page."); | |
| return; | |
| } | |
| // Collect all JPG URLs | |
| const allUrls = new Set(); | |
| mediaWall.querySelectorAll("img").forEach(img => { | |
| if (img.src.includes("zillowstatic.com") && img.src.endsWith(".jpg")) { | |
| allUrls.add(img.src); | |
| } | |
| }); | |
| mediaWall.querySelectorAll("source").forEach(source => { | |
| const srcset = source.getAttribute("srcset"); | |
| if (srcset) { | |
| srcset.split(",").forEach(item => { | |
| const cleanUrl = item.trim().split(" ")[0]; | |
| if (cleanUrl.includes("zillowstatic.com") && cleanUrl.endsWith(".jpg")) { | |
| allUrls.add(cleanUrl); | |
| } | |
| }); | |
| } | |
| }); | |
| // Deduplicate: keep only highest resolution per photo | |
| const map = {}; | |
| [...allUrls].forEach(url => { | |
| const match = url.match(/(.*-cc_ft_)(\d+)\.jpg$/); | |
| if (match) { | |
| const base = match[1]; | |
| const size = parseInt(match[2], 10); | |
| const key = base + "jpg"; | |
| if (!map[key] || size > map[key].size) { | |
| map[key] = { url, size }; | |
| } | |
| } | |
| }); | |
| const deduped = Object.values(map).map(v => v.url); | |
| console.log("✅ Found", deduped.length, "unique JPG images"); | |
| // Build ZIP | |
| const zip = new JSZip(); | |
| const folder = zip.folder(address); | |
| for (let i = 0; i < deduped.length; i++) { | |
| const url = deduped[i]; | |
| console.log("⬇️ Fetching", url); | |
| const resp = await fetch(url); | |
| const blob = await resp.blob(); | |
| folder.file(`image_${i + 1}.jpg`, blob); | |
| } | |
| // Generate ZIP and trigger download | |
| const content = await zip.generateAsync({ type: "blob" }); | |
| saveAs(content, address + ".zip"); | |
| console.log(`📦 Download complete → ${address}.zip`); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment