Привет, Хабр! Сегодня я расскажу о том, как я разработал Telegram-бота для мониторинга цен на Авито. Бот умеет отслеживать изменения цен в объявлениях и уведомлять пользователей об изменениях. В статье я поделюсь всеми этапами разработки, от проектирования до финальной реализации.
Идея создания бота появилась, когда я хотел сделать агента под свои нужды, не буду говорить какие. И дело дошло до автоматизации процесса пользованием авито.
Что умеет бот?
- Поиск объявлений по различным параметрам (название, категория, город, ценовой диапазон) 
- Отслеживание цен в реальном времени 
- Уведомления при изменении цены (настраиваемый порог изменения) 
- Управление списком отслеживаемых объявлений 
- Поддержка нескольких объявлений для каждого пользователя 
Технический стек
- Python 3.9+ 
- python-telegram-bot 20.7 
- aiohttp 3.9.1 
- pydantic 2.5.2 
- python-dotenv 1.0.0 
Структура проекта
avito-monitor/
├── bot.py           # Основной файл бота
├── avito_api.py     # Класс для работы с API Авито
├── config.py        # Конфигурация
├── requirements.txt # Зависимости
└── README.md        # ДокументацияШаг 1: Настройка окружения
python -m venv venv
source venv/bin/activate  # для Linux/macOS
pip install python-telegram-bot requests python-dotenv aiohttp beautifulsoup4 pydantic aiofilesШаг 2: Конфигурация
Создаем файл config.py для хранения настроек:
import os
from dotenv import load_dotenv
load_dotenv()
BOT_TOKEN = os.getenv('BOT_TOKEN')
AVITO_CLIENT_ID = os.getenv('AVITO_CLIENT_ID')
AVITO_CLIENT_SECRET = os.getenv('AVITO_CLIENT_SECRET')
AVITO_ACCESS_TOKEN = os.getenv('AVITO_ACCESS_TOKEN')
# Настройки мониторинга
CHECK_INTERVAL = 300  # 5 минут
MAX_ITEMS_PER_USER = 10
PRICE_CHANGE_THRESHOLD = 5  # процент изменения ценыШаг 3: Реализация API клиента
class AvitoAPI:
    def __init__(self):
        self.base_url = AVITO_API_BASE_URL
        self.access_token = AVITO_ACCESS_TOKEN
        
    async def search_items(self, **params):
        """Поиск объявлений"""
        return await self._make_request('GET', '/items', params=params)
        
    async def get_item_details(self, item_id: str):
        """Получение деталей объявления"""
        return await self._make_request('GET', f'/items/{item_id}')Важные особенности реализации:
- Асинхронные запросы через aiohttp 
- Система повторных попыток при ошибках 
- Автоматическое обновление токена 
- Обработка различных HTTP-статусов 
Шаг 4: Разработка Telegram бота
class AvitoBot:
    def __init__(self):
        self.api = AvitoAPI()
    async def start(self, update, context):
        """Обработчик команды /start"""
        await update.message.reply_text(
            "Привет! Я бот для мониторинга объявлений на Авито..."
        )
    async def check_prices(self, context):
        """Периодическая проверка цен"""
        for user_id, items in user_items.items():
            for item_id, last_price in items.copy().items():
                try:
                    item_details = await self.api.get_item_details(item_id)
                    current_price = float(item_details.get('price', 0))
                    if self._price_changed_significantly(last_price, current_price):
                        await self._notify_user(user_id, item_id, last_price, current_price)
                except Exception as e:
                    logger.error(f"Error checking price: {e}")Шаг 5: Реализация поиска
Поиск реализован в двух форматах:
- Простой: пользователь отправляет только поисковый запрос 
- Расширенный: запрос в формате "Запрос | Категория | Город | Цена от | Цена до" 
async def search_items(self, update, query, category=None, location=None, 
                      price_from=None, price_to=None):
    try:
        # Получаем ID категории и локации если указаны
        category_id = await self._get_category_id(category)
        location_id = await self._get_location_id(location)
        # Выполняем поиск
        results = await self.api.search_items(
            category_id=category_id,
            location_id=location_id,
            search_query=query,
            price_from=price_from,
            price_to=price_to
        )
        await self._send_search_results(update, results)
    except Exception as e:
        logger.error(f"Search error: {e}")Шаг 6: Система мониторинга цен
Мониторинг реализован через job_queue библиотеки python-telegram-bot:
def main():
    application = Application.builder().token(BOT_TOKEN).build()
    job_queue = application.job_queue
    job_queue.run_repeating(avito_bot.check_prices, 
                           interval=CHECK_INTERVAL, first=10)Для простоты я использовал словари для хранения данных (In-memory хранилище):
user_items: Dict[int, Dict[str, float]] = {}  # user_id -> {item_id: last_price}В реальном проекте лучше использовать базу данных (например, PostgreSQL или Redis).
Обработка ошибок
Важный момент - правильная обработка ошибок API:
async def _make_request(self, method, endpoint, params=None, data=None, 
                       retry_count=0):
    if retry_count >= MAX_RETRIES:
        raise Exception(f"Превышено количество попыток")
    try:
        async with session.request(method, url, params=params, 
                                 json=data) as response:
            if response.status == 401:
                await self.refresh_token()
                return await self._make_request(method, endpoint, 
                                              params, data, retry_count + 1)
            # ... остальная обработка
    except aiohttp.ClientError:
        await asyncio.sleep(RETRY_DELAY)
        return await self._make_request(method, endpoint, 
                                      params, data, retry_count + 1)Возможные улучшения
- Добавить поддержку базы данных 
- Реализовать систему фильтров для уведомлений 
- Добавить статистику изменения цен 
- Реализовать поддержку нескольких площадок 
- Добавить систему подписок на поисковые запросы 
Заключение
Разработка бота была интересным опытом. Основные сложности были связаны с:
- Реализацией асинхронных запросов 
- Правильной организацией системы уведомлений 
Исходный код проекта будет доступен на GitHub
P.S. Если у вас есть вопросы или предложения по улучшению бота - пишите в комментариях!
Комментарии (8)
 - nighthtr26.05.2025 14:26- Авито прям вот так за здрасти позволяет себя парсить?  - kbones Автор26.05.2025 14:26- ну грубо говоря да, вот их оферта  - Devastator8226.05.2025 14:26- Возможно я невнимательно читал, но там про работу со своими объявлениями.  - kbones Автор26.05.2025 14:26- ну если ты не будешь монетизировать это, то я думаю, что ничего страшного не случится 
 
 
 
 
           
 
Den_CH
А в каком ИИ вы это сгенерировали?
kbones Автор
midjourney
Max_2D
Много картинок загружать пришлось?
kbones Автор
Да не, 7-8 где-то