Парсинг Юлы через ZennoPoster — полный разбор рабочего кейса

Сбор данных с Юлы через API ZennoPoster
Главное окно ZennoPoster с GET-запросами к API Юлы — собираем объявления без браузера

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

В этой статье разбираю конкретный боевой кейс: какие поля собирал, как строил запросы, почему выбрал API вместо браузера, как боролся с дублями и куда выгружал результат. Материал рассчитан на тех, кто уже открывал ZennoPoster и понимает разницу между кубиками и C#-сниппетами. Если вы новичок — всё равно читайте, но приготовьтесь гуглить базовые термины.

Весь проект делался в ZennoPoster 7.x. В более старых версиях некоторые блоки могут называться иначе, но логика та же.

Что такое Юла и зачем её парсить

Юла — это доска объявлений от VK (бывшая Mail.ru Group). Запустилась в 2015 году как мобильное приложение, позже обзавелась веб-версией. Основной фокус — частные продавцы, но есть и бизнес-аккаунты. По данным SimilarWeb, месячная аудитория Юлы в районе 40-50 миллионов визитов — внушительная цифра для ниши C2C-торговли.

Кому нужен парсинг Юлы:

  • Маркетологам — отслеживать цены конкурентов на конкретные товарные позиции;
  • Риелторам — собирать актуальные предложения по аренде и продаже недвижимости;
  • Бизнес-аналитикам — строить отчёты по спросу и предложению в регионе;
  • Реселлерам — искать товары с заниженной ценой для перепродажи;
  • SEO-специалистам — анализировать тексты объявлений и ключевые слова.

Юла vs Авито: сравнение двух гигантов

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

Критерий Юла (Youla.ru) Авито (Avito.ru)
Парсинг через API Да, открытый API с JSON-выдачей Нет, только через браузер/мобильное API
Сложность обхода защиты Низкая — достаточно User-Agent Высокая — капча, фингерпринты, rate-limit
Скорость сбора 1000 объявлений 2-5 минут (через API) 15-40 минут (через браузер)
Нагрузка на CPU Минимальная, браузер не нужен Высокая, нужен Chrome/FF
Количество объявлений в выдаче ~200 на страницу (JSON) ~50 на страницу (HTML)
Гео-таргетинг в API По координатам и радиусу Только по городу/региону
Номер телефона Часто указан прямо в JSON Скрыт, требует клика "показать"

Разница очевидна. Если ваша задача — массовый сбор данных с доски объявлений, Юла даёт колоссальное преимущество за счёт API. Авито после 2022 года превратился в крепость: капча на каждое действие, постоянная смена DOM-структуры, блокировки IP после 30-50 запросов. Юла, при всех своих недостатках в интерфейсе, для парсинга подходит идеально.

Имейте в виду: парсинг — серая зона. Всегда проверяйте robots.txt и пользовательское соглашение площадки. Собранные данные используйте для внутренней аналитики, не для публикации чужих объявлений на сторонних ресурсах.

Почему API, а не браузер

Многие начинающие специалисты по автоматизации начинают с эмуляции действий пользователя: открыть Chrome, перейти по ссылке, подождать загрузку, скроллить, выдёргивать XPath. Это выглядит логично — мы же имитируем человека. Но в реальности это тупиковый путь для масштабных задач.

Когда я парсил Юлу, у меня была конкретная цель: собрать 5000 объявлений по трём городам за один прогон. С браузером это заняло бы минимум полтора часа и сожрало бы 8 гигабайт оперативки. Через API тот же объём собирается за 12 минут, а ZennoPoster в это время жуёт не больше 300 мегабайт RAM.

Что даёт API-подход в ZennoPoster:

  • Никакого браузера — не нужен Chrome, Firefox или любой другой движок;
  • JSON на выходе — парсите структурированные данные, а не HTML-кашу с дивами внутри дивов;
  • В 5-10 раз быстрее — один HTTP-запрос против полного цикла загрузки страницы;
  • Минимум C# — для простых задач хватает встроенного парсера JSON в кубиках ZP;
  • Zero капчи — API не показывает капчу, в отличие от сайта при частых запросах;
  • Стабильность — структура JSON меняется в разы реже, чем вёрстка сайта.
После перехода на API-парсинг мой процент успешных прогонов вырос с 65% до 98%. Единственные сбои — когда сам сервер Юлы отдаёт 5xx ошибку, тут уж ничего не поделаешь.

Структура GET-запроса к API Юлы

Сердце парсинга — правильно составленный GET-запрос. Юла не требует авторизации для базовых эндпоинтов, не просит API-ключей и не ставит жёстких лимитов. Вот как выглядит типовой запрос:

GET /api/v1/items?category=telefony&location=55.7558,37.6176&radius=10000&sort=date&page=1 HTTP/1.1 Host: youla.ru User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Accept: application/json Accept-Language: ru-RU,ru;q=0.9[/codeblock]

Разберу параметры по косточкам:

Параметр Назначение Пример
category Категория товаров telefony, nedvizhimost, avto
location Координаты центра поиска 55.7558,37.6176 (Москва)
radius Радиус поиска в метрах 10000 (10 км)
sort Сортировка date, price, distance
page Номер страницы выдачи 1
priceMin/priceMax Диапазон цен (необязательный) 1000 / 50000
query Поисковый запрос (необязательный) iphone 12

В ZennoPoster это делается через кубик HTTP-запрос, вкладка GET. Указываете URL с параметрами, заголовки — и готово. Ответ приходит в переменную, которую потом разбираете на составляющие.

Важный нюанс: Юла отдаёт не больше 200 объявлений на один запрос. Если вам нужно больше — собирайте постранично, инкрементируя параметр page в цикле. Я в своём проекте сделал цикл while с проверкой: если ответ содержит массив и длина массива больше 0 — увеличиваем page на 1 и повторяем.

Какие поля извлекаем из JSON

Ответ API приходит в JSON. Вот ключевые поля, которые я забирал в своём кейсе:

{ "items": [ { "id": "abc12345", "title": "iPhone 12 Pro 128GB", "price": 65000, "currency": "RUB", "description": "Отличное состояние, полный комплект...", "phone": "+7 (999) 123-45-67", "location": "Москва, м. Октябрьская", "photos": [ {"url": "https://img.youla.ru/.../1.jpg"}, {"url": "https://img.youla.ru/.../2.jpg"} ], "created": "2024-01-15T10:30:00Z", "url": "https://youla.ru/moskva/telefony/iphone-12-pro-abc12345", "views": 342, "seller_name": "Александр" } ] }[/codeblock]

Каждое поле вытаскиваю через блок Парсинг JSON. В нём указываю путь: для заголовка — items.[*].title, для цены — items.[*].price и так далее. ZennoPoster сам проходит по массиву и складывает значения в списки. Дальше остаётся только свести списки в таблицу.

\u{201c}

Когда заказчик просит собрать телефоны продавцов — самое сладкое. На Авито их прячут, на Юле они часто торчат прямо в JSON. Никаких дополнительных запросов, никаких кликов по кнопке "показать номер". Просто забираешь и радуешься жизни.

Из личного опыта, Разработчик ZennoPoster-проектов

Блоки против C#: что выбрать

ZennoPoster даёт два пути решения любой задачи: собирать логику из встроенных кубиков (визуальное программирование) либо писать код на C# в сниппетах. У каждого подхода свои плюсы.

Для проекта с Юлой я выбрал смешанный подход. Основная логика — кубики: они наглядны, легко отлаживаются через пошаговое выполнение. Но когда нужно распарсить сложную вложенность JSON с условиями — тут C# незаменим. Три строчки LINQ делают то, на что ушло бы десяток кубиков сравнения и фильтрации.

Когда использовать кубики:

  • Простой линейный парсинг без ветвлений;
  • Быстрое прототипирование — за 20 минут собрать и проверить гипотезу;
  • Передача проекта коллеге, который не пишет на C#.

Когда использовать C#:

  • Нужна фильтрация с условиями (цена больше X И город равен Y);
  • Работа с вложенными массивами и словарями;
  • Математические операции над собранными данными;
  • Экспорт в специфические форматы (свой XML, Excel через EPPlus).
// Пример C# сниппета для фильтрации по цене var items = JArray.Parse(project.Variables["json_response"].Value); var filtered = items .Where(i => (int)i["price"] > 5000 && (int)i["price"] < 100000) .Select(i => new { title = i["title"].ToString(), price = (int)i["price"], phone = i["phone"]?.ToString() ?? "" }) .ToList(); project.Variables["result_count"].Value = filtered.Count.ToString();[/codeblock]

Хорошая новость: в ZennoPoster можно комбинировать оба подхода. Основной поток — на кубиках, а сложные операции выносить в отдельные C#-сниппеты. Шаблон при этом остаётся читаемым и поддерживаемым.

Если вы только начинаете — начните с кубиков. Они дают 90% функциональности без необходимости учить C#. Код подключайте постепенно, когда упрётесь в ограничения визуального редактора.

Сбор данных: пошаговый алгоритм

При помощи моего любимого ПО ZennoPoster я беру необходимые элементы для запросов GET к API Юлы, затем путём нахождения через формат JSON вставляю информацию либо напрямую в таблицу, либо в список. Проще всего, конечно, найти и завести все данные, а потом уже сортировать по столбцам — таким способом вы минуете участь потери каких-то важных данных.

Пошаговый алгоритм, который я использовал:

  1. Формирую список городов с координатами через Таблицу в ZP. Москва, Питер, Новосибирск — для каждого свой радиус.
  2. Для каждого города запускаю цикл по страницам: отправляю GET-запрос, получаю JSON.
  3. Разбираю JSON через блок "Парсинг JSON" — поля title, price, phone, description, photos, url, location, date.
  4. Складываю всё в промежуточный Список (List в ZP), по одному списку на поле.
  5. После завершения цикла свожу списки в Таблицу: список заголовков — в первый столбец, цен — во второй и так далее.
  6. Запускаю Удаление дублей — встроенная функция ZP, сравниваю по URL объявления.
  7. Экспортирую результат в Excel (XLSX) через кубик "Сохранение таблицы".

На выходе получается аккуратная таблица, готовая к анализу. Заказчик доволен, я не потратил лишних нервов на обход капчи и отладку XPath.

Обработка ошибок и защита от сбоев

Любой скрипт, работающий с внешним API, обязан предусматривать отказоустойчивость. Юла — не исключение. Бывает, сервер отвечает 502 Bad Gateway, иногда меняется формат полей (добавляются новые, убираются старые), иногда просто обрывается соединение.

Что я встроил в проект для стабильности:

  • Проверка HTTP-статуса. После каждого запроса проверяю код ответа. Если 200 — работаем дальше. Если 429 (слишком много запросов) — жду 30 секунд и повторяю. Если 5xx — делаю до трёх попыток с паузой в 10 секунд.
  • Валидация JSON. Перед разбором проверяю, что ответ действительно валидный JSON, а не HTML-страница с ошибкой или пустая строка.
  • Защита от пустых полей. Если phone не указан — пишу "не указан", а не оставляю пустую ячейку. Заказчику важно видеть разницу между "нет данных" и "забыли собрать".
  • Логирование через project.Log. Каждый проблемный запрос пишется в лог с номером страницы и кодом ошибки. После прогона можно быстро оценить масштаб проблем.
  • Удаление дублей. У ZennoPoster есть встроенная функция удаления дубликатов — грех не воспользоваться. Сравниваю по URL объявления, потому что один и тот же товар может попасть в разные выборки (например, по смежным категориям).

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

Форматы экспорта: куда выгружать результат

ZennoPoster поддерживает несколько форматов экспорта данных. Выбор зависит от того, что с этими данными будут делать дальше.

Формат Плюсы Когда использовать
Excel (XLSX) Удобен для анализа, фильтрации, сводных таблиц Передача заказчику, внутренняя аналитика
CSV Легковесный, открывается где угодно Импорт в CRM, базы данных, Google Sheets
JSON Сохраняет структуру, вложенность Дальнейшая обработка в скриптах, API-интеграция
Google Sheets (через API) Доступ из любой точки, совместная работа Командная работа над данными

В моём кейсе заказчику нужен был Excel — классика. Но если вы собираете данные для автоматической загрузки в свою базу, JSON будет правильным выбором.

Советы по оптимизации скорости

Несколько приёмов, которые я вывел за годы работы с ZennoPoster и парсингом API:

  • Собирайте всё в списки, потом в таблицу. Не дёргайте таблицу на каждой итерации цикла — это медленно. Сначала накопите данные в списках, потом одной операцией перенесите в таблицу.
  • Отключите логирование лишнего. По умолчанию ZP пишет в лог каждый чих. На больших объёмах это создаёт тормоза. Оставьте только ошибки.
  • Используйте многопоточность. Если собираете данные по нескольким городам — запускайте их параллельно. ZennoPoster поддерживает многопоточное выполнение.
  • Кешируйте категории. Список категорий не меняется годами. Загрузите его один раз в начале проекта и используйте из переменной, а не дёргайте API ради каждой мелочи.
Соблюдая эти правила, я довёл скорость сбора с 2 объявлений в секунду до 12. На объёме в 5000 позиций разница — 42 минуты против 7.

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

Законно ли парсить Юлу через API?

Формально — серая зона. Открытый API не требует авторизации, но пользовательское соглашение может ограничивать автоматизированный сбор. Всегда изучайте актуальные правила площадки. Данные используйте для внутренней аналитики, а не для создания клонов сайта. На практике тысячи компаний ежедневно парсят доски объявлений для мониторинга цен и анализа рынка.

Можно ли парсить Юлу без ZennoPoster?

Можно. Подойдёт любой HTTP-клиент: Python с библиотекой requests, Node.js с axios, даже curl из командной строки. ZennoPoster просто удобнее для не-программистов за счёт визуального редактора и встроенных кубиков обработки JSON. Если вы пишете на Python — задача решается строчек за 50.

Нужен ли прокси для парсинга Юлы?

При небольших объёмах (до 1000 объявлений за раз) прокси не нужен. При интенсивном сборе (10 000+ объявлений в день) рекомендую пул из 3-5 прокси с ротацией. ZennoPoster поддерживает прокси из коробки — можно указать список и настроить смену по таймауту или количеству запросов.

Как часто меняется структура JSON у Юлы?

Реже, чем вёрстка сайта, но всё же меняется. В среднем — 1-2 раза в год. Рекомендую раз в квартал прогонять тестовый сбор по одной странице и сверять список полей. Если что-то пропало или переименовалось — правите пути в блоке "Парсинг JSON" за 5 минут.

Сколько объявлений можно собрать за один прогон?

Зависит от количества страниц в выдаче. Юла отдаёт до 200 объявлений на страницу, максимальная глубина — около 50 страниц. Теоретический предел — 10 000 объявлений по одному запросу. На практике редко нужно больше 2-3 тысяч. Мой рекорд — 8 500 объявлений за 25 минут.

Что делать, если Юла заблокировала IP?

Блокировка IP — редкость для Юлы, в отличие от Авито. Но если случилась — меняйте прокси или перезапускайте роутер (для динамического IP). В крайнем случае можно добавить задержки между запросами: 2-3 секунды на страницу — и блокировок не будет.

Можно ли парсить мобильное API Юлы?

Да, и в некоторых случаях мобильный API отдаёт чуть больше данных (например, точную геолокацию продавца). Но в целом веб-API покрывает 95% потребностей. Для мобильного API потребуется подменить User-Agent на мобильный.

Чем отличается парсинг через ZennoPoster от скрипта на Python?

Python-скрипт легче развернуть на сервере, дешевле (бесплатно против платной лицензии ZP) и проще автоматизировать через cron. ZennoPoster выигрывает в визуальной отладке, встроенных инструментах (капча-сервисы, эмуляция браузера, планировщик) и низком пороге входа для не-программистов. Выбор зависит от ваших навыков и задач.

Безопасно ли открывать API Юлы в ZennoPoster?

Да, это обычные HTTP-запросы, никакого криминала. ZennoPoster не отправляет ваши данные разработчикам. Единственный риск — если вы превысите лимиты запросов, IP могут временно заблокировать. Но это проблема решается прокси.

Можно ли собирать архивные объявления с Юлы?

API отдаёт только активные объявления. Закрытые и архивные через API недоступны. Если вам нужна история цен — придётся наладить регулярный сбор и хранить снапшоты самостоятельно, например раз в сутки.

Типичные ошибки при парсинге Юлы

За годы работы с парсингом я насмотрелся на одни и те же грабли, на которые наступают новички. Вот пятёрка самых частых:

  • Забывают про User-Agent. Без нормального заголовка Юла иногда отдаёт 403. Всегда подставляйте актуальный User-Agent из браузера, не поленитесь обновить его раз в месяц.
  • Не проверяют формат даты. В JSON дата приходит в UTC, а заказчику нужна московская. Три часа разницы могут поломать отчёт, если данные идут в аналитику по дням.
  • Парсят без паузы. Даже к лояльному API нельзя стучаться без перерыва. Между страницами ставьте задержку в 500-1000 миллисекунд — это убережёт от неожиданных банов и сократит количество 5xx ошибок.
  • Собирают всё подряд без фильтрации. Зачем тащить в таблицу объявления трёхлетней давности? Добавьте фильтр по дате: только за последние 7 или 30 дней. Объём данных сократится в разы, а качество вырастет.
  • Хранят фото как прямые ссылки. Через месяц ссылки протухнут. Если заказчику нужны изображения — скачивайте их сразу в папку и привязывайте локальные пути.

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

Скачать ZennoPoster (официальный сайт)

Нажмите для реакции