Язык: Python 3.10+ · Стек: httpx · BeautifulSoup4 · Playwright · openpyxl · asyncio Параллелизм: asyncio + Worker Pool · Протокол: HTTP/2 · Анти-детект: ✓
Консольное приложение для автоматизированного сбора и структурирования данных каталога интернет-магазина chitai-gorod.ru. Спроектировано как production-ready решение для конкурентного анализа цен книжного рынка: регулярно собирает карточки книг, валидирует их по схеме данных и выгружает в форматах, готовых к открытию в MS Excel и интеграции с внешними аналитическими системами.
|
|
|
|
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
- 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 100chitai-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 |
Безголовый режим |
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-файл решает все эти проблемы разом.
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[✅ Готово]
| Уровень защиты | Реализация |
|---|---|
| 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- Базовый пайплайн парсинга
- Многопоточный режим (asyncio)
- Fallback на Playwright
- Многоформатный экспорт (CSV × 3 + XLSX)
- Валидация схемы данных
- Unit-тесты (pytest)
- Incremental scraping (запоминание собранных ID)
- Webhook-уведомления о завершении сбора
- Docker-контейнер
- Grafana-дашборд для метрик
- Поддержка официального API (если появится)
Скрипт предназначен для сбора публично доступных данных каталога. Использование должно соответствовать:
- 📜 Пользовательскому соглашению сайта-донора
- 🇷🇺 Действующему законодательству РФ (включая 152-ФЗ)
- 🤝 Этическим нормам (вежливые задержки, отсутствие DoS-нагрузки)
Перед боевым использованием рекомендуется:
- Согласовать объём и частоту запросов с администрацией
chitai-gorod.ru - Использовать официально предоставляемый API, если таковой имеется
- Настроить
MIN_DELAY/MAX_DELAYс учётом нагрузки на сайт-донор
Проект распространяется на условиях лицензии MIT. Подробности см. в файле LICENSE.
⭐ Если проект оказался полезным — поставьте звезду!