Полнофункциональный загрузчик книг с bibliotekus.artlebedev.ru в PDF с автоматической оптимизацией качества и размера.
- Описание
- Возможности
- Структура проекта
- Установка
- Быстрый старт
- Компоненты
- Настройка качества
- Инструменты
- Формат данных
- Сборка EXE
- Безопасность EXE
- FAQ
- Лицензия
Bibliotekus Downloader — консольная утилита для автоматического скачивания книг с библиотеки Студии Артемия Лебедева в формате PDF. Проект состоит из основного загрузчика и набора вспомогательных инструментов:
- Main — главный загрузчик с интерактивным меню, настройкой качества и graceful shutdown.
- Verify — проверка скачанной библиотеки, переименование файлов, список для перекачки.
- Builder — сборка автономного EXE через PyInstaller с генерацией иконки.
- Tests — 50+ юнит и интеграционных тестов всех компонентов.
- 🔍 Автоопределение разрешения — находит максимальное доступное качество (до 2400px) для каждой книги
- 📉 Умная оптимизация — динамический подбор JPEG-качества и resize под целевой размер PDF
- ⚙️ Настройка качества — 4 готовых пресета (30-200 МБ) + полностью ручные параметры
- ⚡ Многопоточность — до 12 потоков на загрузку страниц одной книги
- 📝 Гибкий выбор — номера, диапазоны, комбинации (
1,5-10,20-) - ⏭️ Пропуск скачанных — идентификация по уникальному slug в имени файла
- 🛡️ Graceful shutdown — Ctrl+C корректно завершает текущую книгу и возвращает в меню
- 🔄 Цикл работы — после скачивания выбор: вернуться в меню или выйти
- 📊 Детализированная статистика — время, успех/ошибки, размер файлов
- 🔎 Сканирование — анализ папки
books_pdf/и сопоставление с сайтом - 🔄 Переименование — старые форматы →
Название [slug].pdf - ✅ Проверка страниц — сравнение количества страниц в PDF с сайтом (через PyMuPDF, опционально)
- 📋 Список перекачки — готовая строка для ввода в main downloader
- 🏗️ Сборка в EXE — автономный исполняемый файл (~45 МБ)
- 🎨 Генерация иконок — автоматическое создание
.icoчерез Pillow - 🧹 Очистка — удаление build/, dist/, кеша
📂 Нажмите, чтобы развернуть дерево файлов
bibliotekus-downloader/
├── __main__.py # Точка входа — скачивание книг
├── config.py # Единая конфигурация
├── utils.py # Общие утилиты
├── logger.py # Логирование (консоль + файл)
├── network.py # HTTP-сессия с retry/backoff
├── scraper.py # Парсинг сайта: книги, страницы, разрешения
├── downloader.py # Оркестрация загрузки
├── image_optimizer.py # Оптимизация изображений
├── pdf_builder.py # Сборка PDF (fpdf2 + reportlab)
├── cli.py # Интерфейс: меню, выбор, настройки
├── requirements.txt # Зависимости Python
├── .gitignore
├── README.md
├── LICENSE
├── scripts/
│ ├── __init__.py # Описание скриптов
│ ├── tests.py # Тесты проекта
│ ├── verify.py # Проверка библиотеки
│ ├── builder.py # Сборка EXE
│ └── checksum.py # Генерация SHA-256
├── assets/
│ └── icon.ico # Иконка для EXE
└── data/ # Создаётся автоматически
├── books_pdf/ # Скачанные книги
└── bibliotekus.log # Лог-файл
- Python 3.10+
- pip
pip install -r requirements.txt📄 Содержимое requirements.txt
# ─── Основные ──────────────────────────────
requests>=2.28.0
beautifulsoup4>=4.11.0
Pillow>=9.0.0
fpdf2>=2.7.0
# ─── Фоллбэк PDF (опционально) ─────────────
reportlab>=3.6.0
# ─── Проверка библиотеки (опционально) ─────
# PyMuPDF>=1.23.0
# ─── Сборка EXE (опционально) ──────────────
# pyinstaller>=6.0.0
python __main__.pyОткроется интерактивное меню:
══════════════════════════════════════════════════════════════
📚 BIBLIOTEKUS DOWNLOADER
══════════════════════════════════════════════════════════════
📋 Список книг (95 доступно)
✅ Скачано: 10 ⬚ Осталось: 85
──────────────────────────────────────────────────────────────
1. ⬜ Информационная архитектура в интернете
2. ✅ 47.8M Искусство шрифта
3. ⬜ Модульные сетки
...
──────────────────────────────────────────────────────────────
⚙ PDF ~80 МБ | JPEG 78-92% | Мин. 1200px
──────────────────────────────────────────────────────────────
📝 Команды:
y — все книги | new — нескачанные | n — отмена
5 | 1,3,5 | 5-20 | 5- | 1-10,15,20-
settings — настройка качества
──────────────────────────────────────────────────────────────
Что скачать?
| Ввод | Действие |
|---|---|
y / Enter |
Все книги |
new |
Только нескачанные |
5 |
Книга №5 |
1,3,5 |
Перечисление |
5-20 |
Диапазон |
5- |
С 5-й до конца |
1-10,15,20- |
Комбинация |
settings |
Меню настройки качества |
n |
Отмена |
Что скачать? settings════════════════════════════════════════════════════════════
⚙ НАСТРОЙКА КАЧЕСТВА
════════════════════════════════════════════════════════════
Текущие: PDF ~80 МБ | JPEG 78-92% | Мин. 1200px
────────────────────────────────────────────────────────────
Пресет Название PDF МБ JPEG % Мин.px
────────────────────────────────────────────────────────────
low Экономный 30 65-78 800
medium Стандарт 80 78-92 1200 ◄
high Высокое 200 88-96 1600
max Максимум 9999 95-98 2400
────────────────────────────────────────────────────────────
custom Ввести свои значения
back Назад
══════════════════════════════════════════════════
🏁 ГОТОВО за 12.3 мин!
✅ 5 | ❌ 0
📁 5 файлов, 0.39 ГБ
══════════════════════════════════════════════════
──────────────────────────────────────────────────
⏎ Enter — в меню | q — выйти:
Точка входа приложения. Главный цикл работы с graceful shutdown.
| Функция | Описание |
|---|---|
main() |
Главный цикл: меню → выбор → скачивание → возврат в меню |
_handle_sigint() |
Обработка Ctrl+C → флаг _shutdown_requested |
┌──────────┐ ┌───────────┐ ┌──────────────┐ ┌──────────┐
│ Меню │───▶│ Выбор │───▶│ Скачивание │───▶│ Итоги │
│ книг │ │ книг │ │ (downloader)│ │ (CLI) │
└──────────┘ └───────────┘ └──────────────┘ └─────┬────┘
▲ │
└──────────────────────────────────────────────────────┘
⏎ Enter — в меню | q — выйти
Интерфейс командной строки: меню книг, выбор, настройка качества, итоги.
| Функция | Описание |
|---|---|
display_book_list() |
Отображение списка книг с бейджами (✅/⬜) и размерами |
prompt_selection() |
Запрос выбора книг с валидацией |
quality_settings_menu() |
Интерактивное меню настройки качества |
print_summary() |
Итоговая статистика после скачивания |
# Парсинг через utils.parse_ranges()
"1,5-10,20-" → [1, 5, 6, 7, 8, 9, 10, 20, 21, ..., 95]
"new" → [индексы нескачанных книг]Парсинг HTML: получение списка книг, страниц, автоопределение разрешения.
| Функция | Описание |
|---|---|
get_book_links() |
Парсит главную страницу → список {"title", "url", "slug"} |
get_page_count_and_images() |
Парсит страницу книги → количество страниц + URLs изображений |
detect_best_resolution() |
Пробует разрешения 2400→1600→1200→800px HEAD-запросами |
# Пробует в порядке убывания качества
resolutions = [2400, 1600, 1200, 800]
for res in resolutions:
test_url = page_urls[0].replace("/1200/", f"/{res}/")
if safe_head(test_url).status_code == 200:
return res
return 800 # fallbackОркестрация загрузки: многопоточное скачивание → оптимизация → сборка PDF.
| Функция | Описание |
|---|---|
download_book() |
Загрузка одной книги: страницы → оптимизация → PDF |
_process_book() |
Внутренняя функция обработки книги |
_download_single_page() |
Потокобезопасная загрузка одной страницы |
1. Определить разрешение (scraper.detect_best_resolution)
2. Получить URLs страниц (scraper.get_page_count_and_images)
3. Скачать страницы параллельно (ThreadPoolExecutor, 12 потоков)
4. Оптимизировать изображения (image_optimizer.smart_optimize_image)
5. Собрать PDF (pdf_builder.build_pdf_from_files)
6. Сохранить в data/books_pdf/
with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS_PAGES) as ex:
futures = {ex.submit(_download_single_page, t): t[0] for t in tasks}
for future in concurrent.futures.as_completed(futures):
if _shutdown_requested:
ex.shutdown(wait=False, cancel_futures=True)
breakДинамическая оптимизация JPEG под целевой размер PDF.
| Функция | Описание |
|---|---|
smart_optimize_image() |
Подбирает качество и resize для достижения target_size_per_page |
1. Загрузить изображение (Pillow)
2. Если ширина > min_resolution → ресайз с сохранением пропорций
3. Определить уровень сжатия на основе compression_needed:
- < 30% → quality_max
- 30-50% → (quality_min + quality_max) / 2
- > 50% → quality_min
4. Сохранить оптимизированное изображение# Пресет medium: PDF ~80 МБ, книга ~200 страниц
target_per_page = 80 * 1024 * 1024 / 200 # ~400 КБ/страница
# Исходное: 3000x4000, 2.5 МБ
# После оптимизации: 1200x1600, ~350 КБ, JPEG 84%Сборка PDF из оптимизированных изображений.
| Функция | Описание |
|---|---|
build_pdf_from_files() |
Главная функция сборки (fpdf2 → reportlab фоллбэк) |
_build_fpdf() |
Сборка через fpdf2 (приоритет) |
_build_reportlab() |
Фоллбэк через reportlab |
# Каждая страница = одно изображение на всю страницу
for image_path in sorted(image_paths):
pdf.add_page()
pdf.image(str(image_path), x=0, y=0, w=page_width, h=page_height)HTTP-сессия с автоматическими retry через urllib3.
| Функция | Описание |
|---|---|
create_session() |
Создаёт requests.Session с настроенным retry |
safe_get() |
GET-запрос с автоматическим retry |
safe_head() |
HEAD-запрос с автоматическим retry |
# Автоматический retry через urllib3.util.retry.Retry
retry = Retry(
total=MAX_RETRIES,
backoff_factor=RETRY_BACKOFF,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["GET", "HEAD"],
raise_on_status=False,
)
adapter = HTTPAdapter(
pool_connections=POOL_CONNECTIONS,
pool_maxsize=POOL_MAXSIZE,
max_retries=retry,
)
s.mount("https://", adapter)
s.mount("http://", adapter)Единая конфигурация проекта.
# Пути
PROJECT_ROOT # Корень проекта (с поддержкой PyInstaller)
DATA_DIR # data/
OUTPUT_DIR # data/books_pdf/
# Сеть
BASE_URL = "https://bibliotekus.artlebedev.ru"
MAX_RETRIES = 3
RETRY_BACKOFF = 0.5 # экспоненциальный backoff
MAX_WORKERS_PAGES = 12
# Пресеты качества
QUALITY_PRESETS = {
"low": {"target_mb": 30, "quality": (65, 78), "min_res": 800},
"medium": {"target_mb": 80, "quality": (78, 92), "min_res": 1200},
"high": {"target_mb": 200, "quality": (88, 96), "min_res": 1600},
"max": {"target_mb": 9999, "quality": (95, 98), "min_res": 2400}
}# Определение корня проекта
if getattr(sys, "frozen", False):
# Запущены как EXE — берём папку где лежит .exe
return os.path.dirname(sys.executable)
else:
# Обычный запуск — папка где лежит config.py
return os.path.dirname(os.path.abspath(__file__))Общие утилиты проекта.
| Функция | Описание |
|---|---|
sanitize_filename(text) |
Безопасное имя файла (убирает спецсимволы, обрезает до 180 символов) |
make_ranges() |
Парсит выбор книг (1,5-10,20-) → список индексов |
prompt_continue() |
Запрос "⏎ Enter — в меню | q — выйти" |
get_pdf_filename() |
Генерирует имя PDF: Название [slug].pdf |
Настройка логирования: консоль + файл data/bibliotekus.log.
# Формат
[2026-03-03 18:00:00] INFO: Скачивание «Искусство шрифта» (47.8 МБ)
[2026-03-03 18:05:12] ERROR: Не удалось загрузить страницу 5
# Логирование в файл
handler = FileHandler("data/bibliotekus.log", encoding="utf-8")| Пресет | PDF МБ | JPEG % | Мин. px | Назначение |
|---|---|---|---|---|
low |
~30 | 65-78 | 800 | Экономия места, чтение на экране |
medium |
~80 | 78-92 | 1200 | По умолчанию. Баланс качества и размера |
high |
~200 | 88-96 | 1600 | Качественная коллекция |
max |
∞ | 95-98 | 2400 | Архивное качество, оригинальное разрешение |
📝 Введите значения (Enter — оставить текущее):
Целевой размер PDF, МБ [80]: 120
Мин. JPEG качество, % [78]: 85
Макс. JPEG качество, % [92]: 95
Мин. разрешение, px [1200]: 1600
✅ Применены настройки:
PDF ~120 МБ | JPEG 85-95% | Мин. 1600px
Проверка скачанной библиотеки.
python -m scripts.verify- Сканирует
data/books_pdf/и показывает все файлы - Сопоставляет с книгами на сайте по slug и названию
- Переименовывает файлы старого формата →
Название [slug].pdf - Проверяет количество страниц в PDF vs на сайте (требует PyMuPDF, опционально)
- Выдаёт готовую строку для перекачки повреждённых/неполных
══════════════════════════════════════════════════════════════
📊 ИТОГИ
══════════════════════════════════════════════════════════════
✅ ОК: 89
❌ Не скачаны: 4
🔻 Неполные: 2 (меньше страниц, чем на сайте)
💀 Повреждены: 0
🔄 ПЕРЕКАЧАТЬ: 6 книг
📋 Для bibliotekus.exe введите:
3,15,42-44,78
──────────────────────────────────────────────────
⏎ Enter — выйти | любая клавиша — продолжить:
Сборка автономного EXE через PyInstaller.
python scripts/builder.py════════════════════════════════════════════════════════════
🔨 BUILDER — Сборка bibliotekus.exe
════════════════════════════════════════════════════════════
Точка входа: __main__.py
Иконка: ✅ assets/icon.ico (45.2 КБ)
────────────────────────────────────────────────────────────
✅ 45.2 MB (2026-03-03 18:00) 1. Собрать bibliotekus.exe
────────────────────────────────────────────────────────────
2. Перегенерировать иконку
3. Очистить build/
4. Очистить dist/
5. Очистить всё (build + dist)
q. Выход
# Если assets/icon.ico отсутствует — генерирует через Pillow
img = Image.new('RGBA', (256, 256), color='#3776AB')
draw = ImageDraw.Draw(img)
draw.text((64, 96), '📚', font=..., fill='white')
images.save('assets/icon.ico', format='ICO')50+ юнит и интеграционных тестов.
python -m scripts.tests # все тесты
python -m scripts.tests -v # подробный вывод| Группа | Тесты |
|---|---|
| Утилиты | sanitize_filename, parse_ranges, get_pdf_filename |
| Конфиг | Пути, пресеты, PyInstaller-режим |
| Оптимизатор | Подбор качества, ресайз, валидация |
| PDF Builder | Сборка через fpdf2/reportlab |
| CLI | Парсинг выбора, меню качества |
| Scraper | Моки для get_book_links, detect_best_resolution |
| Интеграция | Полный цикл: скрапинг → оптимизация → PDF |
| Shutdown | Graceful завершение, флаг _shutdown_requested |
data/books_pdf/
├── Искусство шрифта [art-of-type].pdf # 47.8 МБ, 234 стр
├── Модульные сетки [grid-systems].pdf # 52.1 МБ, 196 стр
└── ...
<Название книги> [<slug>].pdf
# Примеры:
Искусство шрифта [art-of-type].pdf
Grid Systems in Graphic Design [grid-systems].pdf
# Установить зависимости
pip install pyinstaller pillow
# Запустить builder
python scripts/builder.py
# Выбрать: 1 — Собрать bibliotekus.exe
# Результат:
# dist/bibliotekus.exe (~45 МБ)# Положить data/ рядом с exe (или создастся автоматически)
bibliotekus.exe
# Книги сохраняются в:
# <папка с exe>/data/books_pdf/EXE-файл собран через PyInstaller из открытого исходного кода данного репозитория. PyInstaller упаковывает интерпретатор Python и зависимости в один файл, что часто вызывает ложные срабатывания антивирусов (false positive).
Каждый релиз проверен на VirusTotal (70+ антивирусных движков):
| Файл | Результат | Отчёт |
|---|---|---|
bibliotekus.exe |
✅ 6/70 — AI срабатывания | 🔗 Открыть отчёт |
💡 Как проверить самостоятельно: загрузите EXE на virustotal.com → увидите результат за 1-2 минуты.
<будут сгенерированы при релизе через scripts/checksum.py>
PyInstaller-сборки иногда детектируются эвристикой как «подозрительные», потому что:
- EXE распаковывает Python-рантайм во временную папку при запуске
- Такой же механизм используют некоторые вредоносные программы
- Это не означает, что файл заражён
Решения:
- Проверьте отчёт VirusTotal по ссылке выше
- Сравните SHA-256 хеш скачанного файла с указанным
- Соберите EXE самостоятельно:
python scripts/builder.py - Добавьте файл в исключения антивируса
При первом запуске Windows может показать предупреждение:
"Windows защитила ваш компьютер"
→ Подробнее → Выполнить в любом случае
Это происходит потому, что EXE не подписан цифровой подписью (code signing certificate стоит $200+/год). Предупреждение исчезнет после нескольких запусков.
В папке data/books_pdf/ — рядом с exe-файлом (или рядом с проектом при запуске из Python).
Да, Ctrl+C. Текущая книга завершится корректно, и вы вернётесь в меню. Скачанные книги остаются, при следующем запуске будут пропущены.
- Удалите файл из
data/books_pdf/ - Запустите downloader и выберите номер книги
Или используйте scripts/verify.py для списка повреждённых.
Не должно — после каждого действия есть выбор:
⏎ Enter — в меню | q — выйти
Если всё же закрывается — запустите из cmd/PowerShell чтобы увидеть ошибку.
Скрипт определяет скачанные книги по формату Название [slug].pdf.
Если файл называется иначе — он не распознаётся. Запустите
python -m scripts.verify для переименования.
Введите settings в меню и выберите пресет или задайте свои параметры.
low — маленькие файлы (~30 МБ), max — максимальное качество (∞).
pip install fpdf2Если fpdf2 недоступен, скрипт автоматически использует reportlab.
Это известная особенность PyInstaller — ложное срабатывание. Добавьте файл в исключения. Проверить можно на VirusTotal.
pip install pyinstaller pillow
python scripts/builder.pyПроект распространяется под лицензией MIT — используйте как угодно, но на свой страх и риск.
Программное обеспечение предоставляется «КАК ЕСТЬ» (AS IS), без каких-либо явных или подразумеваемых гарантий, включая, но не ограничиваясь, гарантиями товарной пригодности и пригодности для конкретной цели.
Автор ни при каких обстоятельствах не несёт ответственности за:
- прямые, косвенные, случайные, штрафные или побочные убытки
- потерю данных, прибыли или деловой репутации
- блокировку аккаунтов, IP-адресов, доменов
- нарушение условий использования сторонних сервисов
- любые претензии третьих лиц
- Все скачиваемые материалы являются собственностью их правообладателей
- Сайт bibliotekus.artlebedev.ru — владелец контента
- Пользователь обязан самостоятельно убедиться в законности скачивания и использования материалов в своей юрисдикции
Проект создан исключительно в образовательных и исследовательских целях для демонстрации методов веб-скрапинга на Python. Автор не поощряет нарушение авторских прав или условий использования сайтов.