Les plateformes immobilières sont fortement protégées contre la collecte automatisée de données. CaptchaAI vous aide à maintenir un accès fiable aux listes de propriétés, aux données de tarification et aux analyses de marché.
Protections CAPTCHA sur les sites immobiliers
| Type de plateforme | Protection | Type de CAPTCHA |
|---|---|---|
| Agrégateurs MLS | Cloudflare Challenge | Défi complet + proxy |
| Portails de type Zillow | reCAPTCHA v3 | Invisible, comportemental |
| Annuaires d'agents immobiliers | reCAPTCHA v2 | Case à cocher ou invisible |
| Dossiers de taxe foncière | Image CAPTCHA | Reconnaissance de texte |
| Sites d'enchères | Cloudflare Turnstile | Défi des widgets |
| Annonces commerciales | reCAPTCHA v2 Enterprise | Vérification améliorée |
Collecteur de données de propriété
import requests
import time
import re
import json
import csv
import os
from datetime import datetime
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
def solve_captcha(params):
params["key"] = API_KEY
resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
if not resp.text.startswith("OK|"):
raise Exception(f"Submit: {resp.text}")
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id,
})
if result.text == "CAPCHA_NOT_READY":
continue
if result.text.startswith("OK|"):
return result.text.split("|", 1)[1]
raise Exception(f"Solve: {result.text}")
raise TimeoutError()
class PropertyCollector:
def __init__(self):
self.session = requests.Session()
self.session.headers["User-Agent"] = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0"
)
def fetch(self, url):
"""Fetch page with automatic CAPTCHA handling."""
resp = self.session.get(url)
# reCAPTCHA
match = re.search(
r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', resp.text
)
if match:
# Detect v3
is_v3 = "recaptcha/api.js?render=" in resp.text
params = {
"method": "userrecaptcha",
"googlekey": match.group(1),
"pageurl": url,
}
if is_v3:
params["version"] = "v3"
params["action"] = "search"
token = solve_captcha(params)
resp = self.session.post(url, data={
"g-recaptcha-response": token,
})
# Turnstile
if "cf-turnstile" in resp.text:
match = re.search(r'data-sitekey=["\']([^"\']+)', resp.text)
if match:
token = solve_captcha({
"method": "turnstile",
"sitekey": match.group(1),
"pageurl": url,
})
resp = self.session.post(url, data={
"cf-turnstile-response": token,
})
return resp.text
def collect_listings(self, urls):
"""Collect property listings from multiple pages."""
listings = []
for url in urls:
try:
html = self.fetch(url)
page_listings = self._parse_listings(html)
listings.extend(page_listings)
print(f" {len(page_listings)} listings from {url}")
time.sleep(3)
except Exception as e:
print(f" Error: {url} - {e}")
return listings
def _parse_listings(self, html):
"""Extract property data from HTML."""
listings = []
# Price extraction
prices = re.findall(r'\$\s*([\d,]+)', html)
# Address extraction
addresses = re.findall(
r'class="address"[^>]*>(.*?)</(?:div|span|p)', html
)
# Bed/Bath extraction
beds = re.findall(r'(\d+)\s*(?:bed|br|bedroom)', html, re.I)
baths = re.findall(r'(\d+)\s*(?:bath|ba|bathroom)', html, re.I)
# Sqft extraction
sqft = re.findall(r'([\d,]+)\s*(?:sq\s*ft|sqft)', html, re.I)
# Combine available data
count = max(len(prices), len(addresses), 1)
for i in range(min(count, 50)): # Cap at 50 per page
listing = {
"price": prices[i] if i < len(prices) else None,
"address": (
addresses[i].strip() if i < len(addresses) else None
),
"beds": beds[i] if i < len(beds) else None,
"baths": baths[i] if i < len(baths) else None,
"sqft": sqft[i] if i < len(sqft) else None,
"collected_at": datetime.utcnow().isoformat(),
}
if listing["price"] or listing["address"]:
listings.append(listing)
return listings
def export_csv(self, listings, filename):
if not listings:
print("No listings to export")
return
keys = ["price", "address", "beds", "baths", "sqft", "collected_at"]
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=keys)
writer.writeheader()
writer.writerows(listings)
print(f"Exported {len(listings)} listings to {filename}")
# Usage
collector = PropertyCollector()
search_urls = [
"https://example-realty.com/search?city=austin&type=sale&page=1",
"https://example-realty.com/search?city=austin&type=sale&page=2",
"https://example-realty.com/search?city=austin&type=sale&page=3",
]
listings = collector.collect_listings(search_urls)
collector.export_csv(listings, "austin_listings.csv")
Points de données à collecter
| Champ | Source | Cas d'utilisation |
|---|---|---|
| Prix affiché | Page de propriétés | Valorisation boursière |
| Adresse | Page de propriétés | Géo-analyse |
| Lits/Baths/Sqft | Détails de la propriété | Analyse comparable |
| Jours de marché | Liste des métadonnées | Vitesse du marché |
| Historique des prix | Journal des changements de prix | Analyse des tendances |
| Taxe foncière | Dossiers fiscaux | Analyse des investissements |
| Frais HOA | Détails de l'annonce | Analyse des coûts |
Flux de travail d’analyse de marché
Daily Collection
→ Property listings (500-1000 per market)
→ Price changes (delta from previous day)
→ New listings vs delisted
Weekly Analysis
→ Median price trends
→ Inventory levels
→ Days-on-market averages
→ Price-per-sqft by neighborhood
Monthly Report
→ Market heat map
→ Competitive pricing analysis
→ Investment opportunity scoring
FAQ
Le scraping de données immobilières est-il légal ?
Les données des listes publiques sont généralement récupérables. Évitez de collecter des informations personnelles sur les vendeurs ou les agents. Respectez toujours les conditions d’utilisation du site.
Comment gérer la pagination ?
Incrémentez le paramètre de page dans vos URL. La plupart des sites immobiliers utilisent les modèles ?page=N ou &offset=N.
Quel type de CAPTCHA est le plus difficile sur les sites immobiliers ?
Cloudflare Challenge sur les agrégateurs MLS est le plus complexe : il nécessite des paramètres proxy. reCAPTCHA v3 sur les principaux portails est courant mais résolu de manière fiable par CaptchaAI.
Guides connexes
- Surveillance des prix du commerce électronique
- Meilleures pratiques de configuration du proxy
- Scraper des sites Web protégés