Zillow хранит 160 миллионов записей о недвижимости в США, и собрать данные Zillow с помощью Python в большом объёме — одна из самых востребованных и одновременно самых нервных задач в сфере данных о недвижимости. Если вы уже пытались собирать данные Zillow и вместо карточек объявлений упирались в страницу CAPTCHA, вы точно не одиноки.
Я потратил немало времени, чтобы разобраться и протестировать разные способы собрать данные Zillow с помощью Python и через no-code инструменты, которые мы сделали в Thunderbit. Это руководство покрывает оба пути. Нужен ли вам полноценный разбор на Python с обходом антибот-защиты или просто 200 объявлений в таблице уже к обеду — здесь найдётся подходящий вариант. Разберём, зачем вообще нужны данные Zillow, как сайт устроен изнутри, пошаговый Python-урок, почему парсеры ломаются и как настроить регулярный сбор для отслеживания цен.
Зачем вообще собирать данные Zillow?
Zillow — крупнейшее хранилище данных о жилой недвижимости в США. Платформа получает 210 миллионов визитов в месяц и размещает более 750 000 активных объявлений о продаже и около 1,9 миллиона арендных предложений. На неё приходится свыше 50% всего трафика американских порталов недвижимости — это более чем вдвое больше, чем у ближайшего конкурента.

Прежде чем переходить к коду на Python, важно понять: собрать данные Zillow с помощью Python — далеко не единственный вариант, и если выбрать не тот подход, можно потерять часы работы. Инструменты на Python вроде httpx и BeautifulSoup требуют среднего уровня подготовки, ручной настройки заголовков и прокси, работают со средней скоростью (1–3 секунды на страницу) и нуждаются в регулярной поддержке, хотя сами по себе бесплатны; Selenium или Playwright лучше справляются с антибот-защитой за счёт рендеринга JavaScript, но работают медленнее (5–15 секунд на страницу) и тоже требуют постоянного обслуживания; scraping API вроде ScraperAPI или ScrapFly работают быстрее, имеют встроенную антибот-поддержку и требуют умеренного ухода, но стоят $30–599 в месяц; официальный API Zillow через Bridge Interactive быстрый и почти не требует поддержки, но ограничен по доступу и стоит около $500 в месяц; а no-code инструменты вроде Thunderbit подойдут новичкам, работают быстро, не требуют обслуживания благодаря адаптации на базе ИИ и обычно предлагают freemium-модель.
Экономия времени сама по себе впечатляет. Ручное исследование по 50+ почтовым индексам может съедать 15–20 часов в неделю. Автоматизированный сбор делает ту же работу за минуты — это сокращение времени на 99,7%.
Все способы собрать данные Zillow: Python, API и no-code в сравнении
Прежде чем углубляться в Python, знайте: "scrape Zillow with Python" — это не единственный вариант. Неправильный выбор метода легко отнимает часы. Вот сравнение в лоб, чтобы вы могли выбрать подходящий путь:
| Метод | Уровень навыка | Антибот-защита | Скорость | Поддержка | Стоимость |
|---|---|---|---|---|---|
| Python + httpx/BeautifulSoup | Средний | Вручную (заголовки, прокси) | Средняя (1–3 с/страница) | Высокая (селекторы ломаются) | Бесплатно |
| Python + Selenium/Playwright | Средний | Лучше (рендерит JS) | Медленная (5–15 с/страница) | Высокая | Бесплатно |
| Scraping API (ScraperAPI, ScrapFly) | Средний | Встроенная | Быстрая | Средняя | $30–599/мес |
| Официальный API Zillow (Bridge Interactive) | Начальный–средний | Н/Д | Быстрая | Низкая | ~$500/мес, ограниченный доступ |
| No-Code инструмент (Thunderbit) | Начальный | Встроенная (ИИ адаптируется) | Быстрая | Нет (ИИ перечитывает страницу) | Freemium |
Если данные нужны прямо сейчас и код писать не хочется, начинайте с Thunderbit. Если хотите понять механику или нужна полная кастомизация, читайте дальше Python-разбор.
Способ за 2 минуты: собрать Zillow через Thunderbit без кода
Прежде чем переходить к Python, вот путь для тех, кому нужны данные Zillow быстро — без настройки Python, без прокси и без возни с селекторами. Мы сделали этот сценарий в Thunderbit специально для структурированного сбора данных о недвижимости без лишней инженерной боли.
Сложность: Начальный уровень Время: ~2 минуты Что нужно: Браузер Chrome, расширение Thunderbit для Chrome (достаточно бесплатного тарифа)
Шаг 1: Установите Thunderbit и откройте Zillow
Установите расширение Thunderbit из Chrome Web Store. Перейдите на страницу результатов поиска Zillow — например, выполните поиск домов в Houston, TX.
Шаг 2: Нажмите "AI Suggest Fields"
Откройте боковую панель Thunderbit и нажмите "AI Suggest Fields". ИИ анализирует страницу и автоматически предлагает столбцы: цена, адрес, количество спален, ванных, площадь, Zestimate, URL объявления и многое другое. По моим тестам, он обычно определяет 20+ полей без какой-либо ручной настройки.
Шаг 3: Нажмите "Scrape"
Нажмите кнопку Scrape. Данные появятся в структурированной таблице прямо внутри расширения. Thunderbit автоматически обрабатывает пагинацию Zillow — как по кликам, так и бесконечную прокрутку.
Шаг 4: Обогатите данные через сбор вложенных страниц
Нужны подробности со страницы объекта, например история налогов, рейтинг школ или история цен? Используйте "Scrape Subpages", чтобы дополнить таблицу. Thunderbit переходит по каждой ссылке объявления и забирает дополнительные поля — без лишнего кода.
Шаг 5: Экспортируйте данные
Экспортируйте в Google Sheets, Excel, Airtable или Notion. Экспорт бесплатный.
Почему Thunderbit хорошо работает с Zillow
Главное преимущество здесь — устойчивость. ИИ Thunderbit каждый раз заново читает структуру страницы при сборе данных. Когда Zillow меняет макет сайта — а это происходит часто — вам не нужно чинить хрупкие CSS-селекторы. ИИ сам подстраивается. Это действительно снимает проблему «изначально нестабильных» кодовых парсеров, которая так раздражает многих пользователей.
Какие данные можно собрать на Zillow? Более 20 полей
Большинство гайдов берут только цену и адрес и на этом останавливаются. На самом деле объявления Zillow содержат гораздо больше данных, чем кажется. Вот справочная таблица:
| Поле | Где находится | Сложность извлечения |
|---|---|---|
| Цена объявления | Поиск + страница объекта | Легко |
| Адрес / ZIP | Поиск + страница объекта | Легко |
| Zestimate | Поиск + страница объекта | Легко |
| История цен (каждое событие) | Страница объекта | Сложно (вложенный JSON) |
| История налогов | Страница объекта | Сложно (вложенный JSON) |
| Спальни / ванные / кв. футы | Поиск + страница объекта | Легко |
| Год постройки | Страница объекта | Легко |
| HOA fee | Страница объекта | Средне |
| Walk Score / Transit Score | Страница объекта (iframe) | Сложно (нужен JS-рендеринг) |
| Рейтинги школ | Страница объекта | Средне |
| Размер участка | Страница объекта | Легко |
| Days on Zillow | Поиск | Легко |
| Агент / брокер | Поиск + страница объекта | Средне |
| MLS # | Страница объекта | Легко |
| Тип недвижимости | Поиск + страница объекта | Легко |
| Широта / долгота | JSON __NEXT_DATA__ | Средне |
| Описание | Страница объекта | Легко |
| URL фото | Поиск + страница объекта | Средне |
| Rent Zestimate | Страница объекта | Средне |
| Сопоставимые продажи рядом | Страница объекта | Сложно |
Сложные поля — история цен, налоговая история, сопоставимые продажи — находятся во вложенном JSON на страницах объектов. Ниже в разделе про Python показано, как именно их извлекать. А если не хочется писать код, Thunderbit с помощью AI Suggest Fields сам определяет большинство этих столбцов, а Scrape Subpages автоматически забирает поля со страниц объектов.
Настройка Python-среды для сбора данных Zillow
Сложность: Средний уровень Время: ~5 минут на настройку, ~30 минут на полный разбор Что нужно: Python 3.8+, браузер Chrome (для анализа страниц), текстовый редактор или IDE
Установите нужные библиотеки:
pip install httpx beautifulsoup4 pandas lxml
Что делает каждая из них:
- httpx — HTTP-клиент с лучшей производительностью, чем
requests, и поддержкой async - beautifulsoup4 + lxml — разбор HTML
- pandas — экспорт данных в CSV/Excel
- По желанию: selenium или playwright, если нужно рендерить страницы с тяжёлым JavaScript
Как устроена страница Zillow, прежде чем вы начнёте сбор

Это самое важное, что нужно понять перед написанием кода. Zillow — это приложение на Next.js — это подтверждается публикациями инженеров Zillow. Это означает, что большая часть нужных вам данных не находится в видимых HTML-элементах. Они встроены в JSON-блок внутри <script id="__NEXT_DATA__">.
Откройте любую страницу объекта Zillow, нажмите F12, перейдите во вкладку Elements и найдите __NEXT_DATA__. Вы увидите огромный JSON-объект со всеми данными объявления — ценой, координатами, характеристиками объекта, историей цен, налоговыми записями, рейтингами школ и многим другим.
Почему это важно? CSS-классы Zillow хэшируются (генерируются styled-components) и меняются при каждом деплое. Класс вроде StyledPropertyCardHomeDetailsList-c11n-8-109-3__sc-1j0som5-0 уже через неделю будет иметь совсем другой хэш. Любой парсер, завязанный на CSS-селекторы, будет регулярно ломаться.
Подход через JSON __NEXT_DATA__ намного стабильнее, потому что он вообще не зависит от HTML-структуры.
Ключевые JSON-пути для результатов поиска:
| Путь | Содержимое |
|---|---|
props.pageProps.searchPageState.cat1.searchResults.listResults | Массив результатов поиска |
props.pageProps.searchPageState.cat1.searchResults.mapResults | Результаты в режиме карты |
props.pageProps.searchPageState.cat1.searchList.totalPages | Общее количество доступных страниц |
Для страниц объектов некоторые используют __NEXT_DATA__, а некоторые — альтернативный тег script hdpApolloPreloadedData. Код ниже обрабатывает оба варианта.
Пошагово: как собрать данные Zillow с помощью Python
Шаг 1: Настройте HTTP-заголовки, чтобы не словить мгновенную блокировку
Простой httpx.get() к Zillow вернёт страницу CAPTCHA, а не данные объявлений. Zillow использует PerimeterX (HUMAN Security) вместе с Cloudflare — обе системы оцениваются как сложность 8/10 по бенчмаркам для парсинга. Система проверяет TLS-отпечаток, HTTP-заголовки и репутацию IP.
Вот минимальный набор заголовков, который работает на 2025 год:
import httpx
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
"image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Sec-Ch-Ua": '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
"Sec-Ch-Ua-Platform": '"Windows"',
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
}
Заголовки Sec-Ch-Ua критически важны. Многие статьи их пропускают — и именно поэтому код из таких статей не работает против PerimeterX.
Шаг 2: Сбор результатов поиска Zillow
URL поиска Zillow строятся по предсказуемому шаблону. Для Houston, TX:
- Страница 1:
https://www.zillow.com/houston-tx/ - Страница 2:
https://www.zillow.com/houston-tx/2_p/ - Страница 3:
https://www.zillow.com/houston-tx/3_p/
На каждой странице примерно 41 объявление. Zillow ограничивает выдачу 20 страницами (~820 объявлений). Для больших наборов данных придётся делить поиск по географии — об этом ниже.
Вот код для сбора результатов поиска через JSON __NEXT_DATA__:
from bs4 import BeautifulSoup
import json
import time
import random
def scrape_zillow_search(url):
"""Собирает данные объявлений со страницы результатов поиска Zillow."""
response = httpx.get(url, headers=headers, timeout=15)
if response.status_code != 200:
print(f"Получен статус {response.status_code} для {url}")
return []
soup = BeautifulSoup(response.text, "lxml")
script_tag = soup.find("script", {"id": "__NEXT_DATA__"})
if not script_tag:
print("Не найден __NEXT_DATA__ — вероятно, сработала CAPTCHA-блокировка")
return []
next_data = json.loads(script_tag.string)
try:
results = (
next_data["props"]["pageProps"]["searchPageState"]
["cat1"]["searchResults"]["listResults"]
)
except KeyError:
print("Неожиданная структура JSON — возможно, Zillow изменил формат")
return []
listings = []
for item in results:
listing = {
"zpid": item.get("zpid"),
"address": item.get("addressStreet"),
"city": item.get("addressCity"),
"state": item.get("addressState"),
"zipcode": item.get("addressZipcode"),
"price": item.get("unformattedPrice") or item.get("price"),
"beds": item.get("beds"),
"baths": item.get("baths"),
"sqft": item.get("area"),
"zestimate": item.get("zestimate"),
"days_on_zillow": item.get("daysOnZillow"),
"listing_url": item.get("detailUrl"),
"img_src": item.get("imgSrc"),
"property_type": item.get("hdpData", {}).get("homeInfo", {}).get("homeType"),
"latitude": item.get("latLong", {}).get("latitude"),
"longitude": item.get("latLong", {}).get("longitude"),
}
listings.append(listing)
return listings
Чтобы собрать несколько страниц, просто запустите цикл с паузами:
all_listings = []
base_url = "https://www.zillow.com/houston-tx/"
for page in range(1, 6): # Первые 5 страниц
url = base_url if page == 1 else f"{base_url}{page}_p/"
print(f"Собираю страницу {page}...")
page_listings = scrape_zillow_search(url)
all_listings.extend(page_listings)
# Случайная задержка 3–7 секунд
delay = random.uniform(3, 7)
time.sleep(delay)
print(f"Всего собрано объявлений: {len(all_listings)}")
В all_listings вы должны увидеть структурированные данные по объявлениям. Если результаты пустые, проверьте раздел «Почему парсеры ломаются» ниже.
Шаг 3: Сбор страниц объектов Zillow
Результаты поиска дают базовую информацию. Страницы объектов содержат более глубокие данные: историю цен, налоговую историю, рейтинги школ, информацию об агенте и описание недвижимости. Каждая ссылка из шага 2 ведёт на страницу объекта.
Страницы объектов Zillow используют два возможных формата данных. Вот код, который обрабатывает оба:
def scrape_zillow_detail(url):
"""Собирает подробные данные об объекте со страницы объявления Zillow."""
response = httpx.get(url, headers=headers, timeout=15)
if response.status_code != 200:
return None
soup = BeautifulSoup(response.text, "lxml")
# Сначала пробуем __NEXT_DATA__ (самый распространённый вариант)
script_tag = soup.find("script", {"id": "__NEXT_DATA__"})
if script_tag:
next_data = json.loads(script_tag.string)
try:
cache_str = next_data["props"]["pageProps"]["componentProps"]["gdpClientCache"]
cache = json.loads(cache_str)
first_key = next(iter(cache))
prop = cache[first_key]["property"]
return extract_property_fields(prop)
except (KeyError, StopIteration):
pass
# Запасной вариант: hdpApolloPreloadedData
apollo_tag = soup.find("script", {"id": "hdpApolloPreloadedData"})
if apollo_tag:
raw = json.loads(apollo_tag.string)
api_cache = json.loads(raw["apiCache"])
for key, value in api_cache.items():
if "ForSale" in key or "property" in str(value)[:100]:
prop = value.get("property", value)
return extract_property_fields(prop)
return None
def extract_property_fields(prop):
"""Извлекает структурированные поля из JSON-объекта недвижимости Zillow."""
return {
"zpid": prop.get("zpid"),
"zestimate": prop.get("zestimate"),
"rent_zestimate": prop.get("rentZestimate"),
"description": prop.get("description"),
"year_built": prop.get("yearBuilt"),
"lot_size": prop.get("lotSize"),
"hoa_fee": prop.get("monthlyHoaFee"),
"mls_id": prop.get("mlsid"),
"broker_name": prop.get("brokerName") or prop.get("attributionInfo", {}).get("brokerName"),
"price_history": [
{
"date": event.get("date"),
"event": event.get("event"),
"price": event.get("price"),
}
for event in prop.get("priceHistory", [])
],
"tax_history": [
{
"year": record.get("time"),
"tax_paid": record.get("taxPaid"),
"value": record.get("value"),
}
for record in prop.get("taxHistory", [])
],
"schools": [
{
"name": school.get("name"),
"rating": school.get("rating"),
"distance": school.get("distance"),
}
for school in prop.get("schools", [])
],
}
Пройдитесь по ссылкам объявлений с задержками:
detail_data = []
for listing in all_listings[:10]: # Сначала протестируем на 10
detail_url = listing.get("listing_url")
if not detail_url:
continue
if not detail_url.startswith("http"):
detail_url = f"https://www.zillow.com{detail_url}"
print(f"Собираю детальную страницу: {detail_url}")
detail = scrape_zillow_detail(detail_url)
if detail:
detail_data.append({**listing, **detail})
time.sleep(random.uniform(3, 8))
После этого у вас должен получиться список словарей, содержащих как данные уровня поиска, так и данные уровня объекта по каждому объявлению.
Шаг 4: Обработка пагинации для сбора нескольких страниц
Если в районе больше 820 объявлений (лимит в 20 страниц), нужно делить область по географии. Внутренний API Zillow принимает параметры mapBounds. Стратегия такая: разделить карту на квадранты и собирать каждый отдельно.
def split_bounds(bounds):
"""Делит границы карты на 4 квадранта."""
mid_lat = (bounds["north"] + bounds["south"]) / 2
mid_lng = (bounds["east"] + bounds["west"]) / 2
return [
{"north": bounds["north"], "south": mid_lat, "east": bounds["east"], "west": mid_lng},
{"north": bounds["north"], "south": mid_lat, "east": mid_lng, "west": bounds["west"]},
{"north": mid_lat, "south": bounds["south"], "east": bounds["east"], "west": mid_lng},
{"north": mid_lat, "south": bounds["south"], "east": mid_lng, "west": bounds["west"]},
]
Для большинства задач — например, мониторинга 50–200 объявлений в конкретном районе — достаточно обычной пагинации по URL. Подход с квадрантами нужен для городского или регионального сбора.
Шаг 5: Экспортируйте собранные данные Zillow
Сохраните всё в CSV через pandas:
import pandas as pd
df = pd.DataFrame(detail_data)
df.to_csv("zillow_houston_listings.csv", index=False)
print(f"Экспортировано {len(df)} объявлений в zillow_houston_listings.csv")
Экспорт в JSON:
with open("zillow_houston_listings.json", "w") as f:
json.dump(detail_data, f, indent=2)
Если вы хотите пропустить этап экспорта, Thunderbit бесплатно выгружает данные в Google Sheets, Airtable и Notion — это удобно, если вам нужен сразу совместный формат для работы.
Почему парсеры Zillow ломаются и как сделать их устойчивыми
Это руководство по выживанию.
По моему опыту, парсеры ломаются на Zillow по трём конкретным причинам — и у каждой есть понятное решение.
PerimeterX и CAPTCHA: почему запросы возвращают пустые данные
Интеграция PerimeterX на Zillow одновременно проверяет несколько сигналов: TLS-отпечаток, HTTP-заголовки, репутацию IP и паттерны запросов. Когда она видит автоматизацию, вместо данных объявлений возвращается страница CAPTCHA "Press & Hold".
Типичный сценарий сбоя: вы отправляете запрос с дефолтными заголовками Python. В HTML ответа вместо данных объекта находятся скрипты challenge от PerimeterX, а BeautifulSoup не находит тег __NEXT_DATA__.
Решение: используйте полный набор браузероподобных заголовков из шага 1. Если вы делаете больше нескольких десятков запросов, вам также нужна ротация прокси (ниже). Для серьёзного сбора стоит рассмотреть библиотеку вроде curl_cffi с impersonate="chrome" — это единственный Python HTTP-клиент, который может близко повторить TLS-отпечаток настоящего Chrome.
Динамические CSS-селекторы: почему BeautifulSoup возвращает None
Если вы используете CSS-селекторы вроде .list-card-price или классы с хэшами, ваш парсер будет ломаться каждый раз, когда Zillow выкатывает новый код.
Zillow использует styled-components, которые создают классы вроде StyledPropertyCardHomeDetailsList-c11n-8-109-3__sc-1j0som5-0. Хэш-часть меняется при каждой сборке.
Решение: вообще не используйте CSS-селекторы. Извлекайте данные из JSON-блока __NEXT_DATA__, как показано выше. Этот подход годами остаётся стабильным, потому что структура JSON меняется гораздо реже, чем HTML-разметка.
Если HTML всё же приходится парсить, ищите атрибуты data-test (например, data-test="property-card") или используйте частичное совпадение по классу вроде [class*="PropertyCard"]. Но извлечение из JSON — более надёжный путь.
Ротация прокси и exponential backoff: код, переживающий бан IP
Датасентровые IP Zillow блокирует почти сразу. Для стабильного доступа нужны residential-прокси. Безопасный темп: 1 запрос каждые 3–8 секунд на IP, не более ~500 запросов в час.
Вот декоратор повторных попыток с экспоненциальным backoff и jitter:
import random
import time
def backoff_with_jitter(attempt, base_delay=2, max_delay=60):
"""Экспоненциальный backoff с полным jitter в стиле AWS."""
delay = min(max_delay, base_delay * (2 ** attempt))
return random.uniform(0, delay)
def fetch_with_retry(url, max_retries=5):
for attempt in range(max_retries):
try:
response = httpx.get(url, headers=headers, timeout=15)
if response.status_code == 200:
return response
if response.status_code in (403, 429):
delay = backoff_with_jitter(attempt, base_delay=5)
print(f"Заблокировано ({response.status_code}). Повтор через {delay:.1f} с...")
time.sleep(delay)
continue
except Exception as e:
if attempt == max_retries - 1:
raise
time.sleep(backoff_with_jitter(attempt))
return None
И простая ротация прокси-пула:
class ProxyPool:
def __init__(self, proxies):
self.proxies = proxies
self.index = 0
self.failures = {}
def get_next(self):
proxy = self.proxies[self.index % len(self.proxies)]
self.index += 1
return {"http://": proxy, "https://": proxy}
def report_failure(self, proxy):
self.failures[proxy] = self.failures.get(proxy, 0) + 1
if self.failures[proxy] > 3:
self.proxies.remove(proxy)
# Использование:
pool = ProxyPool(proxies=[
"http://user:pass@residential1.example.com:8080",
"http://user:pass@residential2.example.com:8080",
])
Из провайдеров прокси DataImpulse предлагает residential-прокси примерно от $1/GB — это самый дешёвый вариант, а IPRoyal и Smartproxy — хорошие решения среднего уровня по $4–7/GB.
Альтернатива без обслуживания
Если вы регулярно собираете данные Zillow и устали чинить сломанные селекторы или управлять пулом прокси, ИИ Thunderbit каждый раз заново читает структуру страницы при сборе. Никаких селекторов, никаких настроек прокси. Это действительно решает проблему хрупкости, из-за которой кодовые парсеры постоянно превращаются в головную боль.
Автоматизируйте сбор Zillow: расписание и мониторинг цен
Каждый инвестор в недвижимость, с которым я говорил, хочет именно этого, а ни одно другое руководство по Zillow этого не раскрывает: регулярный автоматический сбор для отслеживания цен.
Для пользователей Python: cron-задачи и отслеживание изменений цены
Настройте cron-задачу, которая будет запускать ваш парсер раз в неделю и отмечать изменения цен:
import pandas as pd
from datetime import datetime
def detect_price_changes(new_data, historical_file, threshold=0.05):
"""Сравнивает новый сбор с историческими данными и отмечает изменения выше threshold."""
try:
old = pd.read_csv(historical_file)
except FileNotFoundError:
new_data.to_csv(historical_file, index=False)
print("Первый запуск — базовые данные сохранены.")
return pd.DataFrame()
merged = new_data.merge(old, on="zpid", suffixes=("_new", "_old"))
merged["price_change_pct"] = (
(merged["price_new"] - merged["price_old"]) / merged["price_old"]
)
alerts = merged[merged["price_change_pct"].abs() > threshold]
# Добавляем новые данные с отметкой времени
new_data["scraped_at"] = datetime.now().isoformat()
new_data.to_csv(historical_file, mode="a", header=False, index=False)
return alerts
Добавьте это в crontab для еженедельного запуска по понедельникам в 6:00 утра:
0 6 * * 1 cd /path/to/scraper && python zillow_monitor.py
Практический пример: отслеживайте 50 объявлений в Austin, TX каждую неделю. Каждый понедельник скрипт собирает текущие цены, сравнивает их с прошлой неделей и выводит CSV с любым снижением цены более чем на 5%.
Для тех, кто не пишет код: Thunderbit Scheduled Scraper
Функция Scheduled Scraper в Thunderbit позволяет описать интервал обычным языком («каждый понедельник в 9:00»), вставить URL поиска Zillow и нажать Schedule. Данные автоматически выгружаются в Google Sheets при каждом запуске. Никакого Python, никакого cron, никакого сервера для поддержки. Это особенно удобно для риэлторов или операционных команд, которым нужен стабильный мониторинг цен без участия инженеров.
Как собирать данные Zillow ответственно
Несколько правил, чтобы не переходить грань:
- Собирайте только публично доступные данные. Не заходите на страницы за логином или за аутентификацией.
- Соблюдайте разумную частоту запросов. 3–8 секунд между запросами. Не перегружайте сервер.
- Не собирайте личные или приватные данные пользователей. Имена агентов и информация о брокерах в объявлениях публичны; данные аккаунтов пользователей — нет.
- Храните и используйте данные этично. Исследование рынка, инвестиционный анализ и лидогенерация — нормальные сценарии. Спам — нет.
- Правовой контекст: решение hiQ v. LinkedIn подтвердило, что сбор публично доступных данных не нарушает CFAA. Аналогичные принципы поддержало решение Meta v. Bright Data (2024). При этом ToS Zillow ограничивает автоматический доступ, а сам сайт обычно применяет IP-блокировки и CAPTCHA, а не судебные меры. Всегда проверяйте актуальные правила и соблюдайте robots.txt.
Выберите правильный подход к сбору Zillow с Python
Лучший путь зависит от вашей ситуации:
Нужны данные быстро и без кода? Thunderbit позволяет перейти от страницы поиска Zillow к структурированной таблице примерно за 2 минуты. ИИ адаптируется к изменениям интерфейса, обрабатывает пагинацию и бесплатно экспортирует данные. Установите расширение Chrome и попробуйте на странице поиска Zillow.
Хотите полный контроль? Используйте Python-код из этого руководства. Извлекайте данные из JSON __NEXT_DATA__ вместо CSS-селекторов — так надёжнее. Настройте браузероподобные заголовки. Используйте residential-прокси и exponential backoff для стабильности.
Нужно масштабировать? Scraping API вроде ScrapFly (99% успеха на Zillow) или ScraperAPI берут на себя прокси и CAPTCHA-инфраструктуру за $30–599 в месяц в зависимости от объёма.
Отслеживаете цены во времени? Настройте cron-задачу со скриптом проверки изменения цен или используйте Scheduled Scraper в Thunderbit как решение без обслуживания.
Данные уже есть. Вопрос только в том, сколько инженерного времени вы готовы потратить, чтобы их забрать. Если хотите больше узнать о том, как переносить веб-данные в таблицы, посмотрите наше руководство по сбору данных с сайтов в Excel или подборку статистики Zillow с актуальными данными платформы. Также можно посмотреть обучающие видео на YouTube-канале Thunderbit.
Попробуйте Thunderbit для сбора данных Zillow Get Started Free
Частые вопросы
Можно ли бесплатно собрать данные Zillow с помощью Python?
Да — httpx, BeautifulSoup и pandas бесплатны и с открытым исходным кодом. Компромисс — время: вам придётся самостоятельно управлять заголовками, ротацией прокси и поддержкой селекторов. На первичную настройку стоит закладывать 4–8 часов, а на обслуживание — 4–10 часов в месяц, если Zillow изменит сайт. У Thunderbit тоже есть бесплатный тариф, если вы хотите полностью избежать кодовой рутины.
У Zillow есть официальный API?
Zillow закрыл бесплатный публичный API в сентябре 2021 года. Сейчас доступ идёт через Bridge Interactive, требуется одобрение, стоимость — примерно $500 в месяц, и сервис рассчитан на лицензированных специалистов по недвижимости. Для большинства пользователей — инвесторов, исследователей, агентов, занимающихся анализом рынка, — сбор данных остаётся практичной альтернативой. Zillow по-прежнему публикует бесплатные исследовательские данные в виде CSV-файлов на zillow.com/research/data/, включая Zillow Home Value Index и Zillow Observed Rent Index.
Как не получить блокировку при сборе данных Zillow?
Три вещи: (1) используйте реалистичные браузерные заголовки, включая Sec-Ch-Ua — это заголовок, который большинство руководств пропускает, а PerimeterX проверяет его одним из первых; (2) ротация residential-прокси — datacenter IP блокируются почти сразу; (3) извлекайте данные из JSON __NEXT_DATA__, а не из HTML-селекторов, чтобы не ломаться при изменении макета. Держите частоту запросов на уровне 1 запроса каждые 3–8 секунд на IP. Или используйте инструмент вроде Thunderbit, который автоматически обходит антибот-защиту.
Какой лучший способ собрать Zillow без кода?
AI Web Scraper от Thunderbit — самый быстрый путь. Установите расширение Chrome, откройте страницу поиска Zillow, нажмите "AI Suggest Fields", чтобы автоматически определить столбцы, а затем нажмите "Scrape". Экспортируйте в Google Sheets, Excel, Airtable или Notion без единой строки кода. ИИ каждый раз перечитывает страницу заново, поэтому не ломается, когда Zillow меняет интерфейс.
Как часто Zillow меняет структуру сайта и как это влияет на парсеры?
Zillow выпускает обновления часто — иногда каждую неделю. Поскольку сайт использует styled-components, CSS-классы меняются при каждом деплое, и парсеры, завязанные на CSS-селекторы, регулярно ломаются. Самый устойчивый подход на Python — извлекать данные из JSON-блока __NEXT_DATA__, который меняется гораздо реже. Если нужен вариант без обслуживания, ИИ Thunderbit перечитывает структуру страницы при каждом сборе и автоматически адаптируется к изменениям макета.
Узнайте больше


