Перейти к содержанию

Создание новых парсеров 🕷️

В системе Gifty сбор данных автоматизирован с помощью Scrapy. Эта станица описывает, как правильно создавать, тестировать и масштабировать пауков.


🚀 Основные концепции

1. Как работает Паук (Yield и Генераторы)

В Scrapy методы парсинга — это генераторы. Вместо того чтобы собирать все товары в огромный список и возвращать его в конце (return list), мы используем ключевое слово yield.

Почему это важно?

  • Экономия памяти: Scrapy обрабатывает объекты по одному, как только они "вылетают" из генератора. Это позволяет парсить миллионы товаров, не забивая RAM воркера.
  • Потоковость: Pipeline (цепочка обработки) начинает валидировать и отправлять первый товар, пока паук еще парсит второй.
def parse_catalog(self, response):
    for card in response.css('.card'):
        # Мы "выбрасываем" товар в систему сразу
        yield self.create_product(...)

2. Стратегии: Discovery vs Deep

Система различает две фазы жизни источника:

  • Discovery (strategy="discovery"): Используется для Хабов (главных страниц разделов). Паук ищет ссылки на конечные категории. Результат — объекты CategoryItem.
  • Deep (strategy="deep"): Используется для Списков товаров (Листингов). Паук собирает товары и идет по пагинации. Результат — объекты ProductItem.

🛠️ Реализация Паука

Используйте GiftyBaseSpider в качестве основы. Он берет на себя рутину: инициализацию URL, проброс source_id и выбор нужного метода парсинга в зависимости от стратегии.

Пример реализации

from gifty_scraper.base_spider import GiftyBaseSpider
from gifty_scraper.items import CategoryItem

class MyShopSpider(GiftyBaseSpider):
    name = "myshop"
    site_key = "myshop"

    def parse_discovery(self, response):
        """Фаза 1: Собираем ссылки на подкатегории"""
        for link in response.css('a.category-link'):
            yield CategoryItem(
                name=link.css('::text').get().strip(),
                url=response.urljoin(link.attrib['href']),
                site_key=self.site_key
            )

    def parse_catalog(self, response):
        """Фаза 2: Собираем товары из конкретной категории"""
        for card in response.css('.product-card'):
            yield self.create_product(
                title=card.css('.name::text').get(),
                price=card.css('.price::text').re_first(r'\d+'),
                product_url=response.urljoin(card.css('a::attr(href)').get()),
                image_url=response.urljoin(card.css('img::attr(src)').get()),
                merchant="My Shop"
            )

        # Пагинация
        if self.strategy == "deep":
            next_page = response.css('a.next::attr(href)').get()
            if next_page:
                yield response.follow(next_page, self.parse_catalog)

🏗️ Обработка сложных случаев

Случай: Разная верстка для разных категорий

Иногда внутри одного сайта категории "Одежда" и "Электроника" имеют абсолютно разные селекторы.

Вариант А: Проверка через URL (в коде)

def parse_catalog(self, response):
    if "/electronics/" in response.url:
        return self.parse_electronics(response)
    return self.parse_generic(response)

Вариант Б: Использование Config (через базу) Если вы хотите менять логику без пересборки кода, используйте поле config в таблице parsing_sources. Все данные из него доступны пауку в self.config.

def parse_catalog(self, response):
    title_css = self.config.get('custom_title_css', '.default-title')
    yield self.create_product(
        title=response.css(title_css).get(),
        # ...
    )


🛠️ Тестирование и отладка

Для проверки логики без запуска всей инфраструктуры (Docker/API) используйте специальный скрипт:

python3 scripts/test_spider.py myshop "https://myshop.ru/catalog" --limit 10
  • --limit: Ограничит сбор (например, первые 10 товаров).
  • --output: Имя файла с результатами (по умолчанию test_results.json).
  • --strategy: discovery или deep (по умолчанию deep).

⛓️ Регистрация в системе

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

1. Создание паука

Просто создайте новый файл паука в директории services/gifty_scraper/spiders/. Убедитесь, что у паука задано уникальное имя (name и site_key).

2. Автоматическое обнаружение

Как только вы добавите файл и перезапустите сервис scraper, воркер при старте выполнит команду scrapy list и отправит список всех доступных пауков в Core API.

3. Настройка через Dashboard

После обнаружения новый паук появится в Dashboard (в Telegram боте) со статусом disabled. Чтобы запустить его:

  1. Откройте Dashboard через бота.
  2. Найдите вашего нового паука в списке.
  3. Нажмите кнопку редактирования и укажите:
    • URL: Входная точка (например, ссылка на Sitemap или Hub-страницу).
    • Type: Тип источника (hub, list, sitemap).
    • Strategy: Стратегия (discovery или deep).
    • Interval: Желаемый интервал обновления.
  4. Переведите переключатель в положение Active.

Система сама добавит задачу в очередь при наступлении времени следующей синхронизации.


🚦 Мониторинг и управление (Dashboard)

Для оперативного управления системой парсинга используется Gifty Scraping Dashboard, интегрированный прямо в Telegram Бота (Mini App).

Основные возможности дашборда:

  1. Spider List: Список всех зарегистрированных источников, их текущий статус (waiting, running, error, broken) и время последнего запуска.
  2. Health Check: Визуализация активных воркеров и их "пульса" (heartbeat) из Redis.
  3. Config Editor: Возможность редактирования настроек паука (URL, интервал, глубина парсинга) без изменения кода.
  4. Stats: Агрегированная статистика по количеству спаршенных и новых товаров за последние 24 часа.

Как открыть дашборд:

В главном меню Telegram бота нажмите кнопку "🕷 Парсинг".

Tip

Если дашборд не открывается (белый экран), проверьте, запущен ли сервис dashboard и доступен ли он по HTTPS (требование Telegram).


💡 Рекомендации

  1. Throttling: По умолчанию стоит задержка 1с между запросами. Если сайт блокирует — увеличьте DOWNLOAD_DELAY в settings.py.
  2. CSS vs XPath: Используйте CSS селекторы везде, где это возможно — они проще читаются.
  3. Images: Всегда проверяйте, что image_url — это полная ссылка (используйте response.urljoin).
  4. Batching: Наш Pipeline автоматически группирует товары в пачки перед отправкой в API для экономии ресурсов.