Выиграй 1 ТБ резидентского трафика, iPhone 18 Pro Max + ещё 33 приза$50 на баланс = 1 билетПрисоединиться
Бизнес

Скрейпер Zillow: как парсить данные о недвижимости на Python

Скрейпер Zillow: как парсить данные о недвижимости на Python

Подведите итоги этой статьи с помощью ИИ:

Собирать объявления о продаже жилья по всему городу вручную долго: цены меняются каждый день, и вчерашняя таблица в Excel быстро теряет актуальность. Скрейпер Zillow автоматически выгружает цены, адреса и параметры домов со страниц каталога в готовую таблицу, которую удобно фильтровать, обновлять и сравнивать.

Коротко о главном

  • Учитывайте правила площадки. Правила самого сайта Zillow запрещают автоматический сбор страниц ботами. Для коммерческих проектов используйте открытые статистические таблицы Zillow Research, официальные партнёрские программы компании или другие каталоги недвижимости, которые разрешают автоматическую выгрузку.

  • Сначала проверяйте скрипт на 5-10 объявлениях. Сверьте собранные цены, адреса и параметры комнат с исходными карточками на сайте, прежде чем запускать большой сбор.

  • Следите за переключением страниц и дубликатами. Настройте переход по страницам поиска, удаляйте повторяющиеся дома по уникальному ID объекта (zpid) и оставляйте пустые ячейки там, где данные в объявлении не указаны.

  • Подбирайте прокси под объём и географию задач. Если нужно заходить с IP-адреса конкретного штата или города и сохранять один адрес при переходе из поиска в карточку дома, выбирайте ротационные резидентские прокси. А для постоянной загрузки тяжёлых страниц без подсчёта гигабайтов подойдут безлимитные мобильные прокси (но помните, что прокси меняют только IP-адрес и не отменяют защитных лимитов самого сайта).

  • Не смешивайте разные цены в одном столбце. Записывайте цену продавца из объявления и автоматическую оценку дома от самого сервиса (Zestimate) в разные колонки таблицы, а также сохраняйте дату и время парсинга каждой карточки.

💡

Пример столбцов итогового CSV-файла
zpid,address,listing_status,asking_price,bedrooms,bathrooms,source_url,collected_at

Какие данные может собирать скрейпер Zillow

Набор данных зависит от того, какие именно страницы вы открываете: общую поисковую выдачу, карточки конкретных домов или профили риелторов. В общей выдаче обычно видны только базовые параметры (цена, адрес, число спален и ванных), а внутри карточки дома можно дополнительно забрать текст описания, расчётную оценку стоимости (Zestimate) и историю изменения цены. С телефонами в объявлениях будьте внимательны: обычно там указан номер риелтора или агентства, а не личный телефон хозяина дома.

Перед тем как парсить данные Zillow, определитесь со списком столбцов будущей таблицы. В нашем примере на Python ниже мы собираем только объекты, выставленные на продажу (со статусом FOR_SALE):

Поле

Формат

Что означает в нашем примере

zpid

Обязательная строка

Уникальный ID объекта на сайте; сохраняется как текст и служит для удаления дубликатов.

address

Обязательная строка

Полный адрес объекта из карточки поисковой выдачи.

listing_status

Обязательная строка

Статус FOR_SALE (объявления с другими статусами скрипт пропускает).

asking_price

Число или null

Цена продажи из объявления (в примере указана в долларах США - USD).

bedrooms

Число или null

Количество спален (ноль сохраняется как допустимое число, например для квартир-студий).

bathrooms

Число или null

Количество ванных комнат, включая дробные значения (например, 1.5 при наличии гостевого санузла).

zestimate

Число или null

Ориентировочная стоимость дома по внутренней оценке Zillow (в USD); хранится отдельно от цены продавца.

description

Строка или null

Текст описания из полной карточки выбранного дома.

source_url

Обязательная строка

Прямая ссылка на страницу объявления.

search_source_url

Обязательная строка

Ссылка на страницу поисковой выдачи, на которой было найдено объявление.

collected_at

Дата и время с часовым поясом

Точное время сохранения страницы поиска.

detail_collected_at

Дата и время или null

Время сохранения полной карточки дома (остаётся null, если отдельная страница дома не открывалась).

synthetic

Булево значение

Метка учебных данных: равна true для записей из тестовых HTML-примеров.

Если скрипт разбирает заранее скачанные на компьютер HTML-страницы, он берёт дату их сохранения из файла настроек (sample.json), а при загрузке страниц по сети записывает текущее время ответа сервера. В нашем тестовом примере ниже указаны условные даты.

Пропущенные необязательные поля записываются как null в JSON и остаются пустыми ячейками в CSV. Если же в карточке нет обязательного поля (например, ID или адреса) либо вместо цены попался некорректный текст, скрипт сразу остановится и выдаст ошибку, чтобы в таблицу не попали случайные цифры.

Стоимость аренды, цену прошлой продажи, площадь дома, историю цен и телефоны агентов наш учебный скрипт не собирает - под них нужно прописать отдельные поля в коде. Если будете добавлять их в свою таблицу, создайте под каждый вид цены отдельную колонку (чтобы не путать текущую цену продавца с арендной ставкой или оценкой Zestimate).

Чем собирать данные Zillow: скрипт на Python, готовые парсеры или официальные выгрузки

Выбор способа зависит от того, как часто вам нужны данные и готовы ли вы писать код. Если нужно один раз выгрузить небольшую таблицу в Excel, проще взять готовый облачный парсер или браузерное расширение. А если вы собираете данные регулярно и по своему списку полей, лучше написать скрипт на Python или развернуть свой браузерный скрейпер.

Инструмент или подход

Для каких задач подходит

Что важно учитывать

Собственный скрипт на Python

Сбор любых нужных полей, проверка данных и сохранение в свою базу

Нужно самостоятельно обновлять код при смене вёрстки сайта и следить за правилами доступа.

Yozh Scraper

Регулярный сбор динамических страниц через реальный браузер в Docker

Нужно запустить контейнер у себя на ПК или сервере и настроить шаблон селекторов под нужные страницы.

Расширение для браузера или облачный парсер

Быстрая разовая выгрузка в таблицу без написания кода

Заранее проверьте список доступных полей, лимиты строк на тарифе и стоимость подписки.

Сторонний сервис Scraping API

Загрузка веб-страниц через инфраструктуру внешнего сервиса

Уточните, что именно возвращает сервис: сырой HTML-код страницы или уже готовый JSON с полями объекта.

Официальные выгрузки и партнёрские программы Zillow

Официальные интеграции и аналитика цен по городам и штатам

Проверьте, какие именно показатели есть в таблицах, и изучите условия лицензии.

Перед покупкой подписки на любой готовый сервис проверьте его на 5-10 объявлениях. Посмотрите, заходит ли парсер внутрь карточки дома за подробным описанием или берёт только краткий список из поиска, как он заполняет пустые ячейки и сохраняет ли ID объекта (zpid) вместе с датой выгрузки.

Учитывайте важный момент: если сторонний сервис называется «Zillow API», это ещё не значит, что он принадлежит самой компании Zillow. Чаще всего это обычный сторонний парсер, который сам скачивает страницы сайта и отдаёт данные через свой сервер.

Если вам нужна общая статистика по рынку недвижимости США, загляните на бесплатный портал Zillow Research - там выложены готовые таблицы со средними ценами на жильё, ставками аренды и числом объявлений по городам и штатам. Также у Zillow Group есть официальные партнёрские программы для разработчиков, но они выдают данные только под конкретные одобренные сервисы, а не открывают полную базу всех объявлений сайта.

💡

Подробнее о программах для парсинга без написания кода читайте в нашей статье про веб-скрейперы без кода (No-Code). 

Как парсить Zillow на Python

Ниже мы разберём рабочий скрипт на Python, который извлекает данные из сохранённых HTML-страниц поиска и карточек домов, а затем сохраняет их в файлы CSV и JSON. Мы проверили этот код на тестовых HTML-файлах без отправки запросов к реальному сайту Zillow.

Скрипт открывает одну страницу поиска, отбирает до пяти уникальных объявлений о продаже (FOR_SALE) и подтягивает к одному из домов подробное описание из файла карточки объекта. Лимит в пять объявлений мы поставили просто для удобства примера.

💡

Параметры тестового окружения: Linux x86_64, Python 3.12.14, Requests 2.34.2 и Beautiful Soup 4.15.0. Список нужных библиотек и их версий прописан в файле requirements.txt. Код протестирован 4 ноября 2026 года и повторно проверен 5 ноября 2026 года. Вы можете скачать исходный скрипт на Python, файл зависимостей requirements.txt, тестовый пример, набор автотестов, а также готовые примеры выгрузки в CSV и JSON.

Подготовьте окружение Python и список полей

Распакуйте архив с файлами примера, откройте папку в терминале и создайте виртуальное окружение Python:

python
python3 -m venv .venv

source .venv/bin/activate

python -m pip install -r requirements.txt

В итоговую таблицу попадут ID объекта, адрес, статус объявления, цена продавца, число спален и ванных комнат, ссылки на страницы и время сбора. Если для дома обрабатывается детальная карточка, к записи добавятся оценка Zestimate и текст описания.

Пароли от прокси лучше хранить отдельно от кода. В нашем скрипте настройка HTTP-прокси берёт адрес сервера из переменной окружения ZILLOW_PROXY_URL (а если она не задана, скрипт подключается напрямую). Учитывайте, что скрипт на Python работает сам по себе и не использует прокси-расширения, установленные в вашем браузере Chrome.

В файле sample.json указаны пути к двум тестовым HTML-страницам и время, когда они были сохранены. Когда скрипт разбирает эти файлы, он переносит в итоговую таблицу именно исходное время сохранения страницы, а не текущее время запуска скрипта.

Где искать данные в коде страницы поиска и карточки дома

Перед написанием парсера откройте нужную страницу в браузере и сравните её исходный код (Ctrl+U / View Page Source) с вкладкой элементов в панели разработчика (F12 / DevTools). Так вы сразу увидите, приходят ли цены и адреса в готовом HTML-коде или подгружаются позже через скрипты.

Наш учебный парсер ищет на странице встроенный блок с данными в формате JSON внутри тега:

html
<script id="__NEXT_DATA__" type="application/json">

Затем он забирает список объявлений и параметры дома по этим двум путям внутри JSON:

bash
Search records:

props.pageProps.searchPageState.cat1.searchResults.listResults

Property details:

props.pageProps.componentProps.gdpClientCache

Эти пути настроены под наши тестовые файлы: разработчики сайтов периодически меняют названия вложенных полей, поэтому перед запуском всегда проверяйте актуальную структуру JSON на свежей странице.

Если же нужные цены или описания появляются на странице только после выполнения JavaScript, обычная библиотека Requests их не увидит - она скачивает только исходный HTML-код. Для таких сайтов страницу нужно открывать через автоматизированный браузер (например, Playwright).

Загрузка HTML-страницы и проверка ответа сервера

Функция fetch_html() проверяет код ответа сервера, следит, чтобы запрос не перенаправили на другую страницу (редирект), и проверяет заголовок Content-Type, прежде чем передать HTML-код в парсер:

python
def fetch_html(url):
    url = source_url(url)
    proxy = os.getenv("ZILLOW_PROXY_URL")

    if proxy and urlsplit(proxy).scheme != "http":
        raise ValueError("This example supports an HTTP proxy endpoint only")

    with requests.Session() as session:
        session.trust_env = False

        if proxy:
            session.proxies = {"https": proxy}

        with session.get(
            url,
            timeout=(5, 20),
            allow_redirects=False,
        ) as response:
            if response.status_code != 200:
                raise ValueError(
                    f"Stopped: HTTP {response.status_code}; no automatic retry"
                )

            if response.url != response.request.url:
                raise ValueError("Unexpected final URL")

            source_url(response.url)
            media_type = (
                response.headers.get("Content-Type", "")
                .split(";")[0]
                .lower()
                .strip()
            )

            if media_type not in {"text/html", "application/xhtml+xml"}:
                raise ValueError("Expected an HTML response")

            return response.text

Параметр timeout=(5, 20) задаёт два времени ожидания: 5 секунд даётся на подключение к серверу и 20 секунд - на получение данных (это допустимая пауза между пакетами данных, а не общее время загрузки всей страницы).

Даже если сервер ответил кодом HTTP 200, важно проверить, что именно пришло внутри страницы. Если вместо списка домов открылась страница с капчей или изменилась вёрстка, скрипт должен сразу выдать ошибку, а не молча сохранить пустой файл с нулём объявлений. Следующая функция page_props() проверяет, есть ли на странице блок __NEXT_DATA__ и словарь pageProps:

python
def page_props(html):
    soup = BeautifulSoup(html, "html.parser")
    node = soup.find("script", id="__NEXT_DATA__")

    if node is None:
        raise ValueError(
            "Expected JSON block absent: inspect the returned page"
        )

    try:
        props = json.loads(node.get_text())["props"]["pageProps"]
    except (KeyError, TypeError, json.JSONDecodeError) as exc:
        raise ValueError("Invalid or changed page-data structure") from exc

    if not isinstance(props, dict):
        raise ValueError("Expected a pageProps object")

    return props

Разбор карточек объектов и проверка числовых полей

Скрипт отбирает только объявления о продаже (FOR_SALE), проверяет наличие ID и адреса, а также удаляет повторы по zpid до того, как ограничить список пятью домами. Объявления об аренде и уже проданные дома пропускаются, чтобы арендная плата или старая цена сделки не попали в колонку текущей цены продавца (asking_price).

Если необязательное числовое поле не заполнено, функция оставляет None. А если вместо числа в поле попала текстовая строка или отрицательное значение, функция number() сразу останавливает скрипт с ошибкой:

python
def number(value, positive=False):
    if value is None:
        return None

    if (
        isinstance(value, bool)
        or not isinstance(value, (int, float))
        or not math.isfinite(value)
        or value < 0
        or (positive and value == 0)
    ):
        raise ValueError(
            "Unexpected numeric value; review the field mapping"
        )

    return value

Подгружать отдельную страницу самого дома нужно только тогда, когда вам требуются дополнительные данные изнутри карточки (например, полное описание или оценка Zestimate). При этом ссылка и ID дома (zpid) должны совпадать с объявлением из поисковой выдачи. Скрипт сохраняет оценку Zestimate в отдельную колонку и записывает время обработки детальной страницы.

Главное правило при сборе базы недвижимости - не путать разные виды цен между собой и не заполнять пустые поля примерными значениями.

Запуск скрипта на тестовых файлах и проверка таблиц

Запустите скрипт на подготовленных тестовых страницах:

shell
python zillow_sample.py sample.json --output run-01

Укажите в команде имя новой папки (например, run-01) - скрипт сам создаст её и сохранит туда готовые файлы CSV и JSON. В терминале появится строка:

bash
Saved 2 unique listings to run-01

Вот как выглядит первая сохранённая карточка в формате JSON (все адреса, ссылки и цены в примере условные):

json
{
  "zpid": "9000000001",
  "address": "100 Example Lane, Sample City, TX 00000",
  "listing_status": "FOR_SALE",
  "asking_price": 395000,
  "bedrooms": 3,
  "bathrooms": 2,
  "source_url": "https://www.zillow.com/homedetails/example-property/9000000001_zpid/",
  "search_source_url": "https://www.zillow.com/synthetic-test-city/",
  "collected_at": "2026-11-04T10:00:00+00:00",
  "zestimate": 400000,
  "description": "Synthetic property description for parser testing only.",
  "detail_collected_at": "2026-11-04T10:01:00+00:00",
  "synthetic": true
}

А так выглядят основные колонки в CSV-файле - посмотрите, как во второй строке сохранены пустая цена и ноль спален:

bash
zpid,listing_status,asking_price,bedrooms,bathrooms,zestimate
9000000001,FOR_SALE,395000,3,2,400000
9000000002,FOR_SALE,,0,1,

Сверьте ID домов, цены, пустые ячейки и число удалённых дубликатов с исходными файлами. Во второй строке специально пропущена цена (пустое место между запятыми), но сохранён ноль в колонке спален (0).

Если вы запускаете скрипт на реальных разрешённых страницах по сети, укажите файл со списком рабочих ссылок и добавьте флаг --live (с этим флагом скрипт не примет тестовые учебные файлы). А чтобы проверить работу самого кода, запустите встроенные тесты:

shell
python -m unittest -v

Эти тесты проверяют только правильность работы самого скрипта на вашем компьютере. Прежде чем запускать большой сбор, всегда проверяйте парсер на паре свежих страниц.

Что именно проверяли автотесты

Мы прогнали 13 автоматических тестов (4 и 5 ноября 2026 года) на подготовленных HTML-файлах:

Параметр проверки

Результат

Тестовые файлы

Один файл поисковой выдачи и один файл полной карточки дома.

Карточек в исходном файле

Три объявления до фильтрации дубликатов.

Сохранено в итоговый файл

Два уникальных объекта после удаления одного повтора по zpid.

Отброшено из-за ошибок

Ноль (в тестовом примере все записи корректны).

Записи с пустыми полями

Одна карточка с незаполненными необязательными полями.

Какие поля пропущены

Во второй карточке поля asking_price, zestimate, description и detail_collected_at равны null.

Сверка выгрузки

Новые файлы CSV и JSON полностью совпали с эталонными файлами в архиве.

Пустое значение detail_collected_at у второго дома означает, что для него разбиралась только краткая карточка из поиска (это нормальное поведение, а не сбой загрузки).

Дополнительно тесты проверяют, чтобы скрипт вовремя останавливался при ошибках: например, если сервер вернул код ошибки вместо страницы, перенаправил запрос на другой адрес, отдал повреждённый JSON или карточку без ID. Обращения к реальному сайту Zillow, переключение страниц поиска и работа через прокси в этих локальных тестах не задействовались.

Сбор динамических страниц через браузер в Yozh Scraper

Наш бесплатный опенсорсный инструмент Yozh Scraper на GitHub запускается в Docker и открывает сайты через настоящий браузер Playwright. В нём удобно один раз настроить правила сбора полей (пресет) для динамических страниц, а проверку и сохранение готовых таблиц оставить в своём скрипте на Python.

В базовой версии Yozh Scraper нет готового шаблона под Zillow. Если вы настраиваете его как веб-скрейпер Zillow или другого разрешённого сайта недвижимости, сначала соберите свой пресет с CSS-селекторами или XPath и проверьте его на 2-3 страницах:

  1. Запустите Yozh Scraper в Docker. Склонируйте репозиторий с GitHub, скопируйте файл настроек .env.example в .env и запустите контейнер командой docker compose up --build. Затем откройте адрес http://localhost:8000/api/v1/health, чтобы убедиться, что локальный сервер запущен.

  2. Создайте свой шаблон (пресет) селекторов. Перейдите на страницу документации API http://localhost:8000/docs и создайте пресет с нужными CSS-селекторами или XPath. Назовите его с приставкой user_ (например, user_zillow_property). Протестируйте пресет через запрос POST /api/v1/presets/{name}/test на одной карточке дома, а затем проверьте на второй, чтобы убедиться, что селекторы подходят ко всем объявлениям.

  3. Отправьте тестовую задачу. Передайте ссылку на одну карточку объекта в эндпоинт POST /api/v1/scrape/preset/page, указав имя вашего пресета. Сервер поставит задачу в очередь и вернёт её номер - job_id.

  4. Проверьте собранные поля. Убедитесь, что в ответе вернулись все нужные данные: ID объекта (zpid), адрес, статус объявления, цена, число комнат и ссылка на страницу. Проверьте, чтобы числа были числами, а незаполненные поля оставались со значением null.

  5. Заберите результат в свой скрипт на Python. Настройте в скрипте проверку статуса задачи по адресу GET /api/v1/scrape/{job_id} раз в несколько секунд. Когда задача завершится, скачайте готовый JSON через GET /api/v1/scrape/{job_id}/results, проверьте, нет ли в ответе ошибок, и сохраните данные в таблицу.

💡

Подробную инструкцию по установке и работе с визуальным конструктором селекторов смотрите в нашей статье про скрин-скрейпинг (скрейпинг экрана) - там мы на примерах разбираем, чем чтение данных из окна браузера отличается от обычной загрузки HTML-кода и парсинга по селекторам.

Как настроить переключение страниц (пагинацию) и не терять объявления

Один поисковый запрос на сайте недвижимости редко показывает абсолютно все дома в городе. Список в выдаче зависит от масштаба карты, выбранных фильтров и ограничений самого сайта на число страниц - даже если сверху написано, что найдено несколько тысяч объявлений.

Перед сбором большого каталога решите, что именно у вас будет считаться одной строкой таблицы: частный дом, отдельная квартира, всё здание целиком или конкретное объявление. Например, в многоквартирном доме может продаваться сразу несколько квартир по одному почтовому адресу - их нельзя склеивать в одну запись просто из-за совпадения улицы и номера дома.

В нашем учебном скрипте на Python разбирается только первая страница поиска. Если вы дописываете переключение страниц (пагинацию), следите, чтобы координаты карты, фильтры и сортировка не сбивались при переходе на страницу 2, 3 и далее. Сохраняйте стартовую ссылку с фильтрами в логе, чтобы всегда понимать, по каким параметрам собиралась база.

Обязательно задайте в коде условия остановки: скрипт должен прекращать перебор страниц, если сайт начал отдавать те же самые объявления по кругу, на новой странице нет ни одного нового zpid или достигнут ваш лимит по числу страниц и времени работы. Записывайте причину остановки в лог - тогда вы сразу поймёте, дошёл ли парсер до конца списка сам или прервался из-за ошибки сети.

Если вы объединяете таблицы из нескольких соседних районов, удаляйте дубликаты строго по уникальному ID объекта (zpid) или номеру конкретной квартиры, а не по текстовому адресу.

После каждого запуска сохраняйте в лог четыре простые цифры:

  • Всего найдено карточек (Raw records): сколько всего объявлений прочитал скрипт до удаления повторов.

  • Уникальных объектов (Unique records): сколько карточек осталось после очистки дубликатов.

  • Отброшенных записей (Rejected records): сколько карточек скрипт пропустил из-за ошибок или другого статуса (и почему).

  • Карточек с пустыми полями (Incomplete records): сколько уникальных домов сохранено с незаполненными необязательными полями.

Так вы всегда будете видеть точное число реально собранных карточек, а не ориентироваться на примерный счётчик объявлений в шапке сайта.

Очистка данных Zillow и выгрузка в CSV или JSON

Чтобы в готовой таблице не сбивались фильтры и расчёты, перед сохранением в файл приведите все поля к единому виду и проверьте несколько строк вручную:

  • Сохраняйте почтовые индексы (ZIP) как обычный текст. В ряде штатов США почтовые индексы начинаются с нуля (например, 07030 в Нью-Джерси). Если открыть CSV-файл в Excel как числовое поле, программа уберёт первый ноль, поэтому столбец индекса нужно импортировать именно как текст.

  • Держите разные виды цен в отдельных колонках. Не смешивайте в одном столбце цену продавца из объявления (asking_price), сумму прошлой продажи дома (last_sale_price), месячную аренду и расчётную оценку Zestimate. Для каждого типа цены и валюты создайте своё поле.

  • Указывайте единицы измерения площади. Записывайте площадь дома или участка вместе с единицей измерения (например, квадратные футы sqft или акры), чтобы случайно не сравнивать площадь дома в футах с площадью участка в акрах.

  • Не путайте пустое поле с числовым нулём. Если информация в карточке не указана, ставьте null в JSON или оставляйте пустую ячейку в CSV. Но если в объявлении указано 0 спален (bedrooms: 0) - это квартира-студия, и такой ноль нужно сохранять как число.

  • Добавляйте ссылку на объявление и время парсинга. В каждой строке таблицы должны быть URL карточки (source_url) и точное время сбора (collected_at), чтобы данные всегда можно было открыть и перепроверить.

Таблицы CSV удобны, когда одному объекту соответствует одна строка с простыми полями. А если вы собираете историю изменения цены по датам или список налоговых платежей за несколько лет, сохраняйте данные в формате JSON либо выносите историю цен в отдельную таблицу CSV, привязанную к дому по его zpid.

Если вы отслеживаете цены каждую неделю, не затирайте старые строки новыми - добавляйте свежие записи с новой датой парсинга. Учитывайте, что если объявление пропало из поиска, это ещё не значит, что дом купили: продавец мог временно снять карточку с публикации или объект перестал попадать под ваши фильтры.

Как выглядит запись с пустыми полями в JSON

Вот вторая карточка из нашего тестового примера на Python (адрес и ссылки в ней также условные). Цена в объявлении не указана, поэтому в поле asking_price стоит null, а для квартиры-студии без отдельной спальни сохранено число 0:

json
{
  "zpid": "9000000002",
  "address": "200 Example Lane, Sample City, TX 00000",
  "listing_status": "FOR_SALE",
  "asking_price": null,
  "bedrooms": 0,
  "bathrooms": 1,
  "source_url": "https://www.zillow.com/homedetails/second-example/9000000002_zpid/",
  "search_source_url": "https://www.zillow.com/synthetic-test-city/",
  "collected_at": "2026-11-04T10:00:00+00:00",
  "zestimate": null,
  "description": null,
  "detail_collected_at": null,
  "synthetic": true
}

Такой же принцип проверки полей используйте, если решите добавить в скрипт новые столбцы.

Какие прокси выбрать для парсинга каталогов недвижимости

Через прокси вы задаёте нужную страну, штат или город, с IP-адреса которого ваш скрипт открывает страницы сайта. Выбор тарифа зависит от того, сколько гигабайт уходит на загрузку страниц и нужно ли сохранять один неизменный IP при переходе по каталогу.

Тип прокси

Для каких задач подходит

Стоимость и условия

Ротационные резидентские

Выбор нужной страны, штата и города, смена IP на каждый запрос или удержание одного адреса до 24 часов через sticky-сессии; подходят для парсинга каталогов, сбора данных для ИИ, SEO и анализа рынков.

Базовые пакеты от $4 за ГБ (до $2.50/ГБ на объёме, спецтарифы в каталоге от $2 за ГБ) с бесплатным выбором локации и переносом остатка трафика

Мобильные

Операторские IP-адреса (CGNAT) с безлимитным трафиком позволяют не считать гигабайты, когда браузер постоянно подгружает тяжёлые скрипты и фотографии домов.

LTE/5G от $1.70 в сутки с поддержкой протоколов HTTP, SOCKS5 и UDP

Статичные резидентские ISP

Один постоянный домашний IP-адрес на весь месяц с безлимитным трафиком; удобен для ежедневного мониторинга одних и тех же региональных витрин с неизменного адреса.

От $5.29 в месяц с аптаймом 99.9%

Серверные (дата-центр)

Быстрые серверные прокси IPv4/IPv6 с безлимитным трафиком на выделенных тарифах; подходят для работы с открытыми API, загрузки простых сайтов и технического мониторинга.

От $1.77 в месяц (общие) и от $2.18 в месяц (выделенные) с поддержкой HTTP и SOCKS5

Если вы собираете страницы через браузер на Linux-сервере (например, на Ubuntu 24.04 с Playwright Chromium), проще всего подключить HTTP-прокси с авторизацией по логину и паролю. Пропишите адрес сервера (server), логин (username) и пароль (password) в настройках запуска browser.new_context(proxy=...), подгружая сами доступы из переменных окружения. Помните об особенности браузеров на движке Chromium: они принимают логин и пароль напрямую только для HTTP/HTTPS-прокси (для SOCKS5 в Chromium нужна либо привязка по IP без пароля, либо сторонний проксификатор).

Перед запуском основного парсера откройте через этот же браузер любой сайт проверки IP и убедитесь, что определяются нужный штат и город. Затем протестируйте сбор на 2-3 карточках и проверьте, все ли поля попали в таблицу.

🔥

Проверяйте чистоту адресов перед запуском через чекер IP-адресов в CyberYozh App: быстрая проверка репутации IP и Fraud Score по антифрод-базам.

Как собирать номера телефонов из объявлений и не путать контакты

Прежде чем добавлять сбор телефонов в свой скрипт, посмотрите, какие именно контакты открыты в карточке объявления и как они подписаны на странице.

Главное правило: телефон риелтора или агентства недвижимости - это не личный номер собственника дома. Не записывайте первый попавшийся телефон со страницы объявления в колонку «Телефон владельца» (owner_phone). Всегда забирайте со страницы имя контактного лица и его статус (агент продавца, брокерское агентство, управляющая компания), чтобы точно знать, чей это номер.

Для каждого контакта в карточке сохраняйте четыре поля:

  • Номер телефона: сохраняйте как текст (вместе с добавочным номером ext., если он есть), чтобы Excel не исказил формат записи.

  • Имя и роль: точно так, как указано в объявлении (например, Listing Agent или Property Manager).

  • Ссылка на объявление (Source URL): страница, с которой был взят этот номер.

  • Дата и время сбора (Timestamp): когда именно была сохранена карточка.

Если в объявлении указано несколько номеров (например, личный мобильный агента и общий телефон офиса агентства), записывайте их в разные колонки, чтобы не перепутать, какой номер кому принадлежит. Если телефона в карточке нет, оставляйте null в JSON или пустую ячейку в CSV.

И не забывайте о правилах: даже если телефон риелтора открыто опубликован на сайте, его нельзя без согласия использовать для спам-рассылок или холодного обзвона.

🔥

Для тестирования форм обратной связи и регистрации в онлайн-сервисах вы можете арендовать виртуальный мобильный номер или резидентский номер в личном кабинете CyberYozh App.

Частые ошибки при парсинге Zillow и способы их решения

Если скрипт перестал собирать объявления, сначала посмотрите, где именно возник сбой: не подключается сам прокси-сервер, сайт ограничил частые запросы (выдал капчу или код 429) либо изменилась вёрстка страницы и парсер не находит нужные поля.

Проблема или симптом

Вероятная причина

Что проверить и как исправить

Код HTTP 403 или страница с капчей

Защитная система сайта ограничила автоматический запрос

Посмотрите сохранённый ответ страницы, остановите частые запросы, проверьте репутацию IP во Fraud Score и убедитесь, что выбранный источник разрешает сбор.

Ошибка HTTP 429

Слишком высокая частота запросов (rate limit)

Проверьте заголовок Retry-After в ответе сервера, уменьшите число параллельных потоков и увеличьте паузы между запросами.

Код HTTP 200, но список записей пуст

Сайт вернул страницу-заглушку или обновил структуру JSON

Проверьте итоговый URL (не было ли редиректа), заголовок Content-Type и сохранённый HTML-файл. Убедитесь, что нужные поля есть в исходном коде страницы.

В выгрузку попала только часть объявлений

Сработали ограничения пагинации, фильтры или часть страниц не загрузилась

Проверьте координаты поиска и активные фильтры, посмотрите число пройденных страниц, список отброшенных карточек и причину остановки скрипта.

В таблице дублируются одни и те же дома

Пересеклись соседние поисковые запросы или повторилась страница выдачи

Настройте удаление дубликатов по уникальному ID объекта (zpid), сохраняя при этом отдельные квартиры внутри здания и историю цен по разным датам.

Не собираются телефонные номера

Номер не указан в карточке или изменился селектор блока контактов

Откройте сохранённую страницу и проверьте блок контактов вручную. Если номера на странице нет, оставляйте поле пустым (null).

В столбец цены попали неверные цифры

Перепутаны поля разных видов цен или сбился формат числа

Проверьте, чтобы цена продавца, арендная ставка, цена прошлой сделки и оценка Zestimate записывались строго в свои отдельные столбцы.

Парсер остановился после обновления сайта

Разработчики сайта переименовали классы в HTML или ключи во встроенном JSON

Сравните новую страницу со старым тестовым файлом, обновите пути к ключам JSON или CSS-селекторы и снова проверьте скрипт на 2-3 карточках.

Если же скрипт выдаёт ошибку соединения с самого старта, проверьте правильность IP-адреса, порта, логина и пароля от прокси в переменной окружения. После любых исправлений в коде сначала запустите проверку на 1-2 страницах и только потом включайте полный сбор.

Короткий чек-лист перед запуском парсера

Перед запуском регулярного сбора проверьте свой парсер на 5-10 тестовых карточках: убедитесь, что цены продавцов, оценки Zestimate и пустые ячейки записываются в правильные колонки без искажений. Для простых HTML-страниц достаточно связки Requests и Beautiful Soup на Python, а если карточки подгружаются через JavaScript, подключите браузерный рендеринг через бесплатный инструмент Yozh Scraper.

🦔

Если для работы скрипта вам нужен IP-адрес конкретного штата или города США либо прокси с безлимитным трафиком, выберите подходящий тариф в нашем каталоге прокси и протестируйте его на своей задаче.

 

Полезно?

Поделиться статьей

Часто задаваемые вопросы о парсере Zillow