Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

📚 Chitai-Gorod Parser

Модульный парсер каталога книг с обходом анти-бот защит и многопоточным сбором данных

Python httpx Playwright License: MIT Code style: black

Язык: Python 3.10+ · Стек: httpx · BeautifulSoup4 · Playwright · openpyxl · asyncio Параллелизм: asyncio + Worker Pool · Протокол: HTTP/2 · Анти-детект:


📖 О проекте

Консольное приложение для автоматизированного сбора и структурирования данных каталога интернет-магазина chitai-gorod.ru. Спроектировано как production-ready решение для конкурентного анализа цен книжного рынка: регулярно собирает карточки книг, валидирует их по схеме данных и выгружает в форматах, готовых к открытию в MS Excel и интеграции с внешними аналитическими системами.


✨ Ключевые возможности

🛡️ Обход анти-бот защит

  • HTTP/2 с полным набором заголовков Chrome 124
  • Резидентные/мобильные прокси с ротацией
  • Playwright fallback при стойких блокировках 403/429/502
  • Маскировка navigator.webdriver и stealth-настройки
  • Cookie persistence и имитация пользовательского поведения

⚡ Производительность

  • asyncio Worker Pool (настраиваемое число воркеров)
  • Динамическая очередь задач с приоритезацией
  • Раннее завершение при достижении целевого объёма
  • Вежливые задержки 2–4 сек с микро-джиттером
  • Retry-логика до 3 попыток с паузой 30–60 сек

🧩 Модульная архитектура

  • Слоистое разделение: Network → Parser → Validator → Exporter
  • Стратегии парсинга: __NEXT_DATA__ → JSON-LD → HTML
  • Изолированные модули с единственной ответственностью
  • Immutable Config через frozen dataclass
  • Легко тестируется и расширяется

📊 Многоформатный экспорт

  • CSV UTF-8 BOM (по ТЗ п.4.3)
  • CSV Windows-1251 для устаревших редакторов
  • CSV UTF-16 LE BOM + TAB — 100% Excel-совместимый
  • XLSX (openpyxl) с авторазмером колонок и фильтрами
  • JSON (опционально) для API-интеграций

🏗️ Архитектура

flowchart TD
    %% Node Styling Definitions
    classDef mainNode fill:#1a365d,stroke:#2b6cb0,stroke-width:2px,color:#fff;
    classDef subNode fill:#2d3748,stroke:#4a5568,stroke-width:1px,color:#edf2f7;
    
    A["main.py (CLI)<br/>asyncio.Queue + Worker Pool"]:::mainNode

    subgraph Network ["modules/network.py (Сетевой слой — ничего не знает про книги)"]
        direction LR
        B1["httpx (HTTP/2)<br/>основной путь"]:::subNode
        B2["Retry + Proxy<br/>Pool Rotation"]:::subNode
        B3["Playwright<br/>fallback"]:::subNode
        B1 --> B2 --> B3
    end
    style Network fill:#1a202c,stroke:#4a5568,stroke-width:1px,color:#edf2f7;

    subgraph Parser ["modules/parser.py (Слой экстракции — ничего не знает про сеть)"]
        direction TB
        C1["Стратегия 1: __NEXT_DATA__ JSON (приоритет)"]:::subNode
        C2["Стратегия 2: JSON-LD Product/Book"]:::subNode
        C3["Стратегия 3: HTML-разметка карточек"]:::subNode
        C1 -->|если пусто| C2
        C2 -->|если пусто| C3
    end
    style Parser fill:#1a202c,stroke:#4a5568,stroke-width:1px,color:#edf2f7;

    D["modules/validator.py<br/>Валидация схемы данных по ТЗ п.3.2"]:::mainNode
    E["modules/exporter.py<br/>Многоформатный экспорт: CSV × 3 + XLSX + JSON"]:::mainNode

    %% Connections with labels
    A --> Network
    Network -->|raw HTML| Parser
    Parser -->|"list[BookRecord]"| D
    D -->|valid records| E
Loading

🚀 Быстрый старт

Предварительные требования

  • Python 3.10+ (скачать)
  • pip (обычно идёт в комплекте с Python)
  • (опционально) Playwright Chromium для fallback-режима

Установка

# 1. Клонировать репозиторий
git clone https://github.com/zzzigrok/chitai-gorod-parser.git
cd chitai-gorod-parser

# 2. Создать виртуальное окружение
python3 -m venv .venv
source .venv/bin/activate        # Linux/macOS
# .venv\Scripts\activate         # Windows

# 3. Установить зависимости
pip install -r requirements.txt

# 4. Установить Playwright Chromium (опционально, для fallback-режима)
playwright install chromium

# 5. Создать конфигурацию
cp .env.example .env
#   Отредактируйте .env: укажите категории, лимиты, прокси

Запуск

# Базовый запуск (читает .env)
python main.py

# Переопределение параметров через CLI
python main.py --max-pages 50 --workers 8 --target 5000
python main.py --categories books,fiction,children
python main.py --target 100

📁 Структура проекта

chitai-gorod-parser/
├── main.py                       # Точка входа, CLI, asyncio-пул воркеров
├── requirements.txt              # Python-зависимости
├── .env.example                  # Шаблон конфигурации
├── README.md
│
├── modules/                      # 📦 Бизнес-логика (6 модулей)
│   ├── __init__.py
│   ├── config.py                 # Загрузка .env, immutable Config
│   ├── logger.py                 # Дублированное логирование (консоль + файл)
│   ├── network.py                # HTTP/2 + прокси + Playwright fallback
│   ├── parser.py                 # 3 стратегии экстракции книг
│   ├── validator.py              # Валидация схемы данных
│   └── exporter.py               # Экспорт в CSV/XLSX/JSON
│
├── scripts/                      # 🔧 Вспомогательные утилиты
│   ├── smoke_test.py             # Проверка связи с сайтом
│   └── reencode_csv.py           # Перекодировка CSV без повторного парсинга
│
├── output/                       # 📊 Результаты (создаётся автоматически)
│   ├── chitai_gorod_books_YYYY-MM-DD.csv            # UTF-8 BOM (ТЗ)
│   ├── chitai_gorod_books_YYYY-MM-DD_win1251.csv    # Windows-1251
│   ├── chitai_gorod_books_YYYY-MM-DD_utf16_tab.csv  # UTF-16 LE + TAB
│   └── chitai_gorod_books_YYYY-MM-DD.xlsx           # ★ Рекомендуется
│
└── logs/                         # 📝 Логи (создаётся автоматически)
    └── parser.log                # Уровень ERROR, ежедневная ротация

⚙️ Конфигурация

Все настройки вынесены в файл .env (см. .env.example).

Основные параметры

Параметр По умолчанию Описание
CATEGORIES books Slug'и категорий через запятую
MAX_PAGES 30 Лимит страниц на категорию
TARGET_RECORDS 500 Целевое количество записей
WORKERS 4 Размер asyncio-пула
MIN_DELAY / MAX_DELAY 2.0 / 4.0 Диапазон задержки, сек
MAX_RETRIES 3 Попыток при 403/429/502
RETRY_PAUSE_MIN / MAX 30 / 60 Пауза между retry, сек
PROXY_LIST (пусто) Список прокси через запятую
PROXY_API_URL (пусто) Внешний API для подгрузки прокси
USE_PLAYWRIGHT_FALLBACK true Fallback на браузер
PLAYWRIGHT_HEADLESS true Безголовый режим

CLI-аргументы

python main.py --help

usage: chitai-gorod-parser [-h] [--max-pages N] [--workers N]
                           [--target N] [--categories LIST]

optional arguments:
  --max-pages N      Переопределить MAX_PAGES из .env
  --workers N        Переопределить WORKERS из .env
  --target N         Переопределить TARGET_RECORDS из .env
  --categories LIST  Slug'ы через запятую (например: books,fiction)

📊 Схема данных

Парсер извлекает 8 полей по каждой книге согласно ТЗ п.3.2:

Поле Тип Обяз. Описание
book_id String Уникальный ID книги
title String Полное название
author String Автор («Нет автора» если отсутствует)
price_current Integer Финальная цена, руб.
price_old Integer Цена до скидки (null если без скидки)
availability String «В наличии» / «Предзаказ» / «Нет в наличии»
rating Float 0.0–5.0 (0.0 если нет оценок)
source_url String Абсолютный URL карточки

📤 Выходные форматы

Скрипт генерирует 4 файла с идентичными данными в разных форматах:

Файл Кодировка Разделитель BOM Назначение
*.csv UTF-8 ; ✓ EF BB BF Основной (по ТЗ п.4.3)
*_win1251.csv Windows-1251 ; Для устаревших редакторов
*_utf16_tab.csv UTF-16 LE TAB ✓ FF FE Самый надёжный CSV для Excel
*.xlsx Рекомендуется — нативный Excel-файл

Почему 4 формата? MS Excel с русской локалью плохо распознаёт UTF-8 BOM при двойном клике по CSV: BOM отображается как , а ; не всегда воспринимается как разделитель. XLSX-файл решает все эти проблемы разом.


🔧 Pipeline

flowchart TD
    A[Запуск main.py] --> B[Загрузка .env]
    B --> C[Инициализация прокси-пула]
    C --> D[Наполнение очереди задач<br/>category × page]
    D --> E{Запуск Worker Pool}
    E --> F1[Воркер 1]
    E --> F2[Воркер 2]
    E --> F3[Воркер N]
    F1 --> G[httpx HTTP/2 запрос]
    F2 --> G
    F3 --> G
    G --> H{Статус?}
    H -->|200 OK| I[Парсинг HTML/JSON]
    H -->|403/429/502| J[Пауза 30-60с<br/>+ смена прокси]
    J --> G
    H -->|Все попытки провалены| K[Playwright fallback]
    K --> I
    I --> L[Валидация схемы]
    L --> M[Экспорт в 4 форматах]
    M --> N[✅ Готово]
Loading

🛡️ Стратегии обхода блокировок

Уровень защиты Реализация
TLS fingerprint (JA3) httpx HTTP/2 + заголовки Chrome 124
Behavioural detection Случайные задержки 2–4 сек + микро-джиттер
IP-based bans Ротация резидентных/мобильных прокси из пула
Cookie tracking Сохранение сессии между запросами
JS challenges (Cloudflare) Fallback на Playwright с реальным Chromium
WebDriver detection Маскировка navigator.webdriver = undefined
Rate limiting (429) Автоматическая пауза 30–60 сек + смена IP

📝 Логирование

Канал Уровень Назначение
Консоль INFO Читаемый поток прогресса в реальном времени
Файл logs/parser.log ERROR Критичные инциденты для постмортема
  • Ежедневная ротация логов
  • Хранение последних 14 дней
  • Структурированный формат: дата │ уровень │ модуль │ сообщение

📈 Демонстрационные результаты

В каталоге output/ уже содержится демо-выгрузка:

Метрика Значение
Книг собрано 600
Невалидных записей 0
Категорий 1 (books)
Время сбора ~15 секунд
Страниц пройдено 10
Среднее время страницы 1.7 сек

Пример записи:

book_id:        3157208
title:          Четвертое крыло (обрез с узором). Специальное издание
author:         Ребекка Яррос
price_current:  1999
price_old:      2399
availability:   В наличии
rating:         4,80
source_url:     https://www.chitai-gorod.ru/product/rebekka-arros-cetvertoe-krylo-obrez-s-uzorom-3157208

🛠️ Технологический стек

Категория Технология Версия
Язык Python 3.10+
HTTP-клиент httpx 0.27
HTTP/2 h2 4.1
HTML-парсинг BeautifulSoup4 + lxml 4.12 / 5.3
Браузер fallback Playwright 1.48
XLSX-экспорт openpyxl 3.1
Конфигурация python-dotenv 1.0
Параллелизм asyncio (стандартная библиотека)

🧪 Тестирование

# Smoke-тест: проверка связи с сайтом и работоспособности парсера
python scripts/smoke_test.py

# Перекодировка существующего CSV в другие кодировки (без повторного парсинга)
python scripts/reencode_csv.py

🗺️ Roadmap

  • Базовый пайплайн парсинга
  • Многопоточный режим (asyncio)
  • Fallback на Playwright
  • Многоформатный экспорт (CSV × 3 + XLSX)
  • Валидация схемы данных
  • Unit-тесты (pytest)
  • Incremental scraping (запоминание собранных ID)
  • Webhook-уведомления о завершении сбора
  • Docker-контейнер
  • Grafana-дашборд для метрик
  • Поддержка официального API (если появится)

⚖️ Правовые аспекты

Скрипт предназначен для сбора публично доступных данных каталога. Использование должно соответствовать:

  • 📜 Пользовательскому соглашению сайта-донора
  • 🇷🇺 Действующему законодательству РФ (включая 152-ФЗ)
  • 🤝 Этическим нормам (вежливые задержки, отсутствие DoS-нагрузки)

Перед боевым использованием рекомендуется:

  1. Согласовать объём и частоту запросов с администрацией chitai-gorod.ru
  2. Использовать официально предоставляемый API, если таковой имеется
  3. Настроить MIN_DELAY / MAX_DELAY с учётом нагрузки на сайт-донор

👤 Лицензия

Проект распространяется на условиях лицензии MIT. Подробности см. в файле LICENSE.


⭐ Если проект оказался полезным — поставьте звезду!

About

Модульный асинхронный парсер книг Читай-город (HTTP/2, ротация прокси, Playwright fallback, экспорт в CSV/XLSX).

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages