Comment extraire les données immobilières de Zillow : JSON de recherche, Zestimate, PerimeterX

Zillow fournit ses données de liste sous forme de JSON caché dans la page — vous n'avez jamais besoin d'analyser un seul div. Voici comment utiliser l'API de recherche par limites de carte, contourner la limite de pagination et survivre à PerimeterX.

Zillow détient plus de 110 millions de propriétés et attire environ 245 millions de visiteurs mensuels, ce qui en fait la source par défaut pour les données immobilières aux États-Unis — prix, adresses, chambres, salles de bain, zestimates et estimations de loyer. Il est également protégé par PerimeterX et s'affiche côté client, donc les scrapers naïfs reçoivent un 403 et une page blanche. La bonne nouvelle : Zillow vous fournit ses données sous forme de JSON si vous savez où chercher, et sa recherche est pilotée par des coordonnées de carte que vous pouvez appeler directement. Voici toute l'approche.

Ne parsez pas le HTML — Zillow fournit du JSON

Il n'est pas nécessaire de se battre avec les sélecteurs CSS sur une page de propriété Zillow. L'enregistrement complet de la propriété est intégré en tant que données web cachées dans une balise script. Deux emplacements couvrent presque chaque page : <script id="__NEXT_DATA__"> contient le cache Next.js, et certaines pages utilisent à la place <script id="hdpApolloPreloadedData"> (le cache Apollo GraphQL). Prenez l'un ou l'autre, analysez-le, et vous obtenez un objet propre avec zpid, price, livingArea, bedrooms, bathrooms, latLong, homeStatus, rentZestimate et plus encore :

import json, re, requests

proxy = "http://USER:PASS@gate.quantumproxies.io:8000"
proxies = {"http": proxy, "https": proxy}
HEADERS = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
           "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36",
           "accept-language": "en-US,en;q=0.9"}

def property_json(url):
    r = requests.get(url, headers=HEADERS, proxies=proxies, timeout=20)
    r.raise_for_status()                       # 403 => blocked, rotate IP
    m = re.search(r'id="__NEXT_DATA__"[^>]*>(.*?)</script>', r.text, re.S)
    if m:
        data = json.loads(m.group(1))
        cache = data["props"]["pageProps"]["componentProps"]["gdpClientCache"]
        return next(iter(json.loads(cache).values()))["property"]
    # fallback: Apollo cache
    m = re.search(r'id="hdpApolloPreloadedData"[^>]*>(.*?)</script>', r.text, re.S)
    cache = json.loads(json.loads(m.group(1))["apiCache"])
    return next(v["property"] for k, v in cache.items() if "ForSale" in k)

L'enregistrement intégré est bien plus riche que la page visible. En plus du prix et de l'adresse, vous obtenez zestimate et rentZestimate — les propres évaluations de vente et de location de Zillow — ainsi que homeStatus (à vendre, vendu, à louer), daysOnZillow, la superficie du terrain et de l'habitation, et la latitude et la longitude précises. C'est tout ce dont un modèle de comparables, un pipeline de notation de prospects ou un tableau de bord de marché a besoin, livré sous forme d'un seul objet JSON propre par propriété au lieu d'une douzaine de sélecteurs CSS fragiles qui se cassent lors de la prochaine refonte.

L'API de recherche fonctionne sur des coordonnées de carte

La recherche de Zillow n'est pas axée sur les mots-clés — elle est axée sur la carte. En coulisses, soumettre une recherche déclenche une requête à zillow.com/async-create-search-page-state avec un objet searchQueryState dont le champ principal est mapBounds : quatre chiffres (nord, sud, est, ouest) qui dessinent un rectangle sur la carte. Donnez-lui une boîte de délimitation et il renvoie chaque annonce à l'intérieur, sous forme de JSON structuré :

def search_area(bounds, page=1):
    url = "https://www.zillow.com/async-create-search-page-state"
    body = {
        "searchQueryState": {
            "pagination": {"currentPage": page},
            "mapBounds": bounds,   # {'north':..,'south':..,'east':..,'west':..}
            "filterState": {"sortSelection": {"value": "days"}},
        },
        "wants": {"cat1": ["listResults", "mapResults"], "cat2": ["total"]},
        "requestId": 2,
    }
    r = requests.put(url, json=body, headers=HEADERS, proxies=proxies, timeout=20)
    return r.json()["cat1"]["searchResults"]["listResults"]

# New Haven, CT bounding box
listings = search_area({"north": 41.366, "south": 41.230,
                        "east": -72.827, "west": -73.030})
Diagramme de flux de l'extraction de Zillow à grande échelle : définir une boîte de limites de carte, appeler l'API de recherche pour JSON, récupérer via un proxy résidentiel, et diviser les quadrants pour contourner la limite de résultats
Piloter Zillow par coordonnées de carte : la boîte de délimitation est la requête et les IP résidentielles gardent PerimeterX silencieux.

Contourner la limite de 820 résultats

Zillow ne pagine que 20 pages d'environ 41 éléments, donc une seule recherche est limitée à environ 820 résultats peu importe le nombre de maisons dans la zone. Les marchés denses en cachent des milliers de plus. La solution consiste à diviser récursivement les quadrants : si une boîte de délimitation renvoie le maximum de pages, divisez-la en quatre boîtes plus petites et recherchez chacune ; continuez à subdiviser jusqu'à ce que chaque boîte renvoie moins que la limite. Cette stratégie de zoom peut faire apparaître des centaines de milliers d'annonces d'une seule métropole que la recherche plate ne montrerait jamais — et elle ne subdivise que là où la densité le justifie, donc vous ne gaspillez pas de requêtes sur la campagne vide.

Cela a un coût : chaque subdivision multiplie les requêtes, donc une métropole dense peut transformer une recherche en dizaines. Prévoyez-le — limitez la profondeur de la récursion et ne zoomez que là où le nombre de résultats le justifie, ce que l'algorithme fait pour vous en subdivisant uniquement lorsqu'une boîte atteint encore le maximum de pages. Pour une actualisation nocturne d'une ville entière, la plupart des requêtes se concentrent alors sur la poignée de boîtes du centre-ville dense tandis que les banlieues se résolvent en un seul passage, donc vous dépensez en profondeur exactement là où se trouve l'inventaire et nulle part ailleurs.

PerimeterX est la raison pour laquelle les scrapers naïfs échouent

Le blocage de Zillow n'est pas principalement basé sur le taux ; c'est PerimeterX (maintenant HUMAN) qui profile la requête. Les IP de centre de données, les en-têtes de navigateur manquants et le timing inhumain déclenchent tous un 403 ou un défi — c'est ce qu'un assert status == 200 vérifie réellement. La solution est une requête cohérente et de confiance : proxies résidentiels américains pour que l'IP de sortie ressemble à un acheteur de maison, des en-têtes de navigateur réalistes, et un backoff exponentiel qui tourne vers une nouvelle IP sur tout 403 plutôt que de réessayer celle brûlée. Notre analyse de comment PerimeterX détecte l'automatisation couvre les signaux en profondeur ; la même posture s'applique à Walmart, qui utilise le même fournisseur.

Lorsque PerimeterX se resserre ou que vous préférez ne pas maintenir une flotte de navigateurs, une Scraper API rend la page, tourne les IP résidentielles et efface le défi pour vous, renvoyant le même JSON caché sans la surcharge opérationnelle.

Extraire Zillow derrière PerimeterX avec des IP résidentielles

Panneau de statistiques montrant les 110 millions de propriétés de Zillow, 245 millions de visiteurs mensuels, limite de recherche de 820 résultats, et 600 mille résultats via la division des quadrants
L'échelle est énorme, mais une recherche est limitée à 820 — contourner cette limite est le véritable travail d'ingénierie.

Quand utiliser les registres du comté à la place

Zillow est excellent pour les annonces, les photos et les estimations, mais c'est une source secondaire. Pour la propriété autoritaire, l'historique des ventes et les valeurs évaluées, les bureaux des évaluateurs et des enregistreurs de comté publient des registres publics — souvent via leurs propres portails ou exportations de données en masse. Si votre cas d'utilisation concerne les titres, les comparables ou les données fiscales plutôt que les annonces en direct, les registres au niveau du comté sont plus propres, plus permissifs à collecter, et totalement exempts de PerimeterX. Utilisez Zillow pour le signal de marché et les registres du comté pour la vérité sur le terrain.

Est-il légal d'extraire des données de Zillow ?

Ceci est une information générale, pas un conseil juridique. Les données d'annonces publiquement disponibles — prix, adresses, attributs de propriété — sont généralement considérées comme équitables à collecter à des taux respectueux. Les résultats de Zillow peuvent inclure des données personnelles, cependant : noms d'agents, numéros de téléphone et détails de courtier. Ceux-ci sont protégés par le RGPD et des lois similaires, donc évitez de les collecter et de les stocker sans base légale. Collectez les faits de la propriété, pas les personnes.

Questions fréquemment posées

Puis-je extraire des données de Zillow ?

Oui — les données d'annonces visibles publiquement peuvent être collectées. Zillow intègre chaque enregistrement de propriété sous forme de JSON dans une balise script (__NEXT_DATA__ ou le cache Apollo), et sa recherche fonctionne sur une API de limites de carte que vous pouvez appeler directement. L'obstacle n'est pas l'accès mais PerimeterX, donc vous avez besoin d'IPs résidentielles et d'en-têtes cohérents pour éviter les 403.

Zillow a-t-il une API ?

Zillow propose environ 20 API officielles, y compris les Détails de Propriété et les Données de Quartier, mais elles nécessitent des clés, ont des limites d'utilisation et ne couvrent pas tous les champs ou cas d'utilisation en masse. De nombreuses équipes extraient les pages publiques à la place précisément parce que le JSON caché contient déjà le prix, les chambres, les salles de bain, la superficie, le zestimate et l'estimation de loyer dont elles ont besoin.

Pourquoi mon scraper Zillow obtient-il un 403 ?

Un 403 sur Zillow est presque toujours dû à PerimeterX, pas à une limite de taux. Les IP de centre de données, les en-têtes de navigateur manquants ou incohérents, et le timing de requête robotique le déclenchent tous. Passez à des proxies résidentiels américains, envoyez des en-têtes réalistes, ajoutez un espacement semblable à celui d'un humain, et tournez vers une nouvelle IP à chaque 403 avec un backoff exponentiel plutôt que de marteler celle bloquée.

Comment extraire plus de 820 annonces Zillow d'une zone ?

Une seule recherche est limitée à environ 820 résultats (20 pages de 41). Pour aller plus loin, divisez la boîte de limites de carte en quatre quadrants et recherchez chacun ; subdivisez récursivement tout quadrant qui atteint encore la limite. Cette approche de zoom ne subdivise que les zones denses, donc elle capture l'inventaire complet d'une métropole sans gaspiller de requêtes sur les régions peu denses.

Évitez le HTML et lisez le JSON intégré, pilotez la recherche par les limites de carte, divisez les quadrants pour contourner la limite, et routez tout via des IP résidentielles propres pour rester en avance sur PerimeterX. Faites cela et Zillow devient un flux structuré de données immobilières au lieu d'un mur de 403.

Obtenez le JSON de Zillow sans combattre PerimeterX