Парсер объявлений Авито по фильтрам - это первое, что просят клиенты, когда нужно собрать квартиры до определённой цены в конкретном районе или отслеживать новые объявления о продаже авто с пробегом до 100 000 км. За практику я сделал больше десятка таких скриптов - для риэлторов, автоподборщиков, оптовиков техники, которым важно узнавать о новом объявлении раньше конкурентов. Ниже - рабочий подход на Selenium и Python: построение URL с нужными фильтрами, сбор карточек, обход блокировок и что делать с результатом дальше.
Почему для Авито нужен Selenium, а не requests
Первая попытка почти у всех одинаковая - requests плюс BeautifulSoup. Работает пару запросов, потом Авито возвращает пустую страницу или капчу. Причина в том, что часть контента подгружается через JS, а сам сайт проверяет поведение клиента: смотрит на заголовки, cookies, наличие браузерного движка. Голый HTTP-клиент этой проверки не проходит.
Selenium запускает настоящий Chrome через chromedriver, поэтому в глазах сервера это обычный браузер. Но и тут есть нюанс: стандартный Selenium палится по флагам webdriver в navigator, и Авито это тоже умеет ловить. На практике стабильнее работает связка Selenium с undetected-chromedriver - он патчит бинарник chromedriver и убирает типовые признаки автоматизации.
| Способ | Скорость | Обход защиты | Стабильность на Авито |
|---|---|---|---|
| requests + BeautifulSoup | высокая | слабый - блок за 10-20 запросов | низкая |
| Selenium (стандартный webdriver) | средняя | средний, палится на fingerprint-проверках | средняя |
| Selenium + undetected-chromedriver | средняя | лучший из доступных без платных антидетект-решений | высокая |
| Официальное API объявлений | - | публичного API для парсинга объявлений у Авито нет | - |
Подготовка окружения для парсера объявлений по фильтрам
Ставлю минимальный набор пакетов:
pip install selenium undetected-chromedriver webdriver-manager pandas
Отдельно про версии: если Chrome на машине обновился сам, а chromedriver остался старым, при запуске вылетает SessionNotCreatedException. Поэтому либо держу webdriver-manager, который подтягивает нужную версию автоматически, либо фиксирую версию Chrome в CI явно - для регулярных запусков через cron это надёжнее.
import undetected_chromedriver as uc
options = uc.ChromeOptions()
options.add_argument("--window-size=1366,900")
# headless=False на Авито ведёт себя стабильнее, чем headless=True
driver = uc.Chrome(options=options, headless=False)
driver.implicitly_wait(5)
Как собрать URL с нужными фильтрами Авито
Авито хранит фильтры прямо в query-параметрах адреса, и это упрощает задачу - не нужно кликать по интерфейсу и эмулировать выбор в выпадающих списках, можно сразу сформировать нужный URL. Открываю в браузере страницу с выставленными фильтрами (цена, комнаты, район, сортировка), смотрю на итоговый адрес и переношу параметры в код.
from urllib.parse import urlencode
base_url = "https://www.avito.ru/moskva/kvartiry/sdam/na_dlitelnyy_srok"
filters = {
"pmin": 30000,
"pmax": 55000,
"rooms": "1,2",
"cd": 1, # только объявления с фото
"s": 104, # сортировка по дате публикации
"p": 1, # номер страницы
}
url = f"{base_url}?{urlencode(filters)}"
Ловушка, в которую сам попадал: категория и регион у Авито зашиты в путь, а не в параметры (/moskva/kvartiry/sdam/...), и если клиент присылает список из десяти городов, под каждый нужен свой base_url. Проще сразу собрать словарь городов с их slug и не хардкодить путь.
Бесплатный материал
🎁 Полезный скрипт в подарок
Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.
Без спама. Отписка в 1 клик.
Сбор карточек объявлений: селекторы и ожидания
Авито размечает карточки атрибутами data-marker, и это удобнее, чем цепляться за CSS-классы - классы у них генерируются и меняются при каждом релизе фронтенда, а data-marker живут заметно дольше. Но раз в несколько месяцев верстка всё равно меняется, поэтому селекторы держу в отдельном конфиге, а не хардкожу по всему коду.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver.get(url)
WebDriverWait(driver, 15).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, '[data-marker="item"]'))
)
cards = driver.find_elements(By.CSS_SELECTOR, '[data-marker="item"]')
items = []
for card in cards:
try:
title = card.find_element(By.CSS_SELECTOR, '[itemprop="name"]').text
price = card.find_element(By.CSS_SELECTOR, '[data-marker="item-price"]').text
link = card.find_element(By.CSS_SELECTOR, 'a[data-marker="item-title"]').get_attribute("href")
item_id = card.get_attribute("data-item-id")
items.append({"id": item_id, "title": title, "price": price, "url": link})
except Exception:
continue
WebDriverWait с явным ожиданием обязателен - без него скрипт пытается читать DOM раньше, чем подгрузились карточки, и падает с пустым списком через раз. implicitly_wait в паре с explicit wait не комбинирую - из-за них тайминги начинают конфликтовать и время ожидания становится непредсказуемым.
Обход блокировок при парсинге по фильтрам
Это основная головная боль, если объём выше «пару страниц раз в день». На практике жёсткая пачка запросов без пауз ловит блокировку по IP уже после 40-60 запросов подряд, и снимается она обычно в пределах получаса-часа. Что реально помогает:
- случайная пауза между переходами на страницы -
time.sleep(random.uniform(2, 5)), а не фиксированное значение - ротация User-Agent, если запускаете несколько параллельных сессий
- headless=False для одиночных прогонов - детект headless-режима у Авито работает ощутимо агрессивнее
- прокси с ротацией IP, если нужно опрашивать фильтры чаще, чем раз в 10-15 минут - для разовых выгрузок это избыточно, для мониторинга в реальном времени без этого не обойтись
- не открывать несколько вкладок с одного профиля браузера параллельно - это самый быстрый способ словить капчу на все сразу
Пагинация и сбор данных с нескольких страниц
Авито отдаёт до 50 объявлений на страницу и без авторизации ограничивает глубину пагинации - дальше определённой страницы начинает просить войти в аккаунт или показывает капчу. Для большинства задач по фильтрам этого достаточно, потому что свежие объявления и так оказываются на первых страницах при сортировке по дате.
import random, time
all_items = {}
for page in range(1, 6):
filters["p"] = page
driver.get(f"{base_url}?{urlencode(filters)}")
time.sleep(random.uniform(2, 5))
cards = driver.find_elements(By.CSS_SELECTOR, '[data-marker="item"]')
if not cards:
break
for card in cards:
item = parse_card(card)
if item:
all_items[item["id"]] = item
Дедуп по id объявления обязателен - Авито иногда повторяет карточки на соседних страницах при досортировке результатов, и без словаря с ключом-идентификатором в выгрузке появляются дубли.
Что делать с собранными данными: сохранение и уведомления
Дальше выбор простой: разовая выгрузка или постоянный мониторинг. Для разовой достаточно pandas и CSV или Excel:
import pandas as pd
df = pd.DataFrame(all_items.values())
df.to_excel("avito_filtered.xlsx", index=False)
Для мониторинга новых объявлений храню список уже увиденных id (json или sqlite), при каждом запуске сравниваю с текущей выгрузкой и по новым id отправляю уведомление в Telegram - обычно через aiogram-бота, который клиент потом использует и для других задач, не только для объявлений. Запуск скрипта по расписанию вешаю либо на cron, либо через n8n - там же удобно собрать цепочку «спарсили - отфильтровали по цене - отправили в чат», если логика чуть сложнее одного условия.
Если не хочется собирать парсер с нуля под конкретные фильтры, у меня в библиотеке готовых скриптов есть рабочие заготовки под похожие задачи - быстрее адаптировать существующий код под свой регион и категорию, чем писать заново.
Данные и процессы на автопилоте
Парсинг / Автоматизация
от 20 000 ₽
Подробнее →Частые вопросы
Легально ли парсить объявления Авито по фильтрам?
Сбор публично доступных данных сам по себе не запрещён, но пользовательское соглашение Авито ограничивает автоматизированный сбор контента с сайта. На практике риск для небольших объёмов «для себя» минимален, но если планируете перепродавать базу контактов или парсить в промышленных масштабах - стоит отдельно смотреть на условия конкретного сайта и не собирать персональные данные продавцов сверх того, что и так показано в объявлении.
Как часто можно запускать парсер без блокировки IP?
Для точечного мониторинга по фильтрам без прокси комфортный интервал - раз в 10-15 минут с паузами между запросами внутри самого прогона. Если нужно опрашивать несколько категорий чаще, без ротации прокси блокировка по IP почти гарантирована в течение часа активной работы.
Можно ли обойтись без Selenium и парсить Авито через requests?
Для разовой выгрузки первых страниц иногда получается, если максимально точно подделать заголовки браузера. Но защита у Авито меняется без предупреждения, и то, что работало неделю назад, может отвалиться сегодня. Для регулярной задачи Selenium с undetected-chromedriver даёт предсказуемый результат, requests - нет.
Сколько стоит заказать парсер объявлений Авито под свои фильтры?
Простой скрипт под один город и одну категорию с выгрузкой в Excel - от 20 000 ₽. Если нужен постоянный мониторинг с уведомлениями в Telegram, дедупом и хранением истории - стоимость выше базовой в зависимости от количества фильтров и глубины интеграции с другими сервисами.