DFWebsite_Downloader
Набор утилит для офлайн-зеркалирования сайтов: скачивание HTML-страниц, связанных ассетов и локальный запуск полученной копии.
Проект ориентирован на Python и подходит для:
- статических сайтов;
- смешанных сайтов, где часть контента объявлена в HTML/CSS/JS/JSON;
- диагностического сохранения структуры ресурсов для последующего анализа.
Важное о лицензии
В репозитории используется лицензия PERMISSION REQUIRED LICENSE (PRL) v1.0.
Это означает, что без явного письменного разрешения автора вам не предоставляются права на использование, копирование, модификацию, публикацию и распространение кода.
Подробности — в файле LICENSE.
Возможности
website_downloader.py
- Обход HTML-страниц выполняется только в пределах основного домена стартового URL.
- Загрузка ассетов поддерживает:
- CSS, JS, изображения, шрифты, JSON и прочие ресурсы;
- опциональное скачивание ассетов с внешних доменов (
--external); - запрет отдельных доменов (
--exclude-domain, можно несколько раз).
- Извлечение зависимостей:
- из CSS:
url(...),@import; - из JS: эвристическое извлечение путей/URL из строк;
- из JSON: рекурсивный поиск строковых URL/путей с докачкой ссылок.
- из CSS:
- Поддержка cache-busting query (
?v=...,?t=...):- локальное имя файла получает суффикс
__q_<hash>; - это предотвращает коллизии и помогает корректно раздавать такие файлы локально.
- локальное имя файла получает суффикс
- Дополнительная обработка популярных паттернов:
srcset,data-src,data-srcset;meta-изображения (og:image,twitter:image);video poster,audio/video/source;iframe(внутридоменные добавляются в обход, внешние фиксируются в отчёте).
- Генерация отчёта
download_report.jsonс итоговой статистикой.
serve_site.py
Локальный сервер для каталога скачанного сайта на http://127.0.0.1:8080/ с поддержкой:
- pretty URL fallback:
/lab→/lab.html/dir/→/dir/index.html
- файлов с cache-busting query:
/assets/app.css?v=123→/assets/app__q_<hash>.css
- fallback на уже сохранённые варианты
__q_*даже при запросе без query.
Как это работает
- Скрипт начинает со стартового URL и формирует очередь страниц.
- Для каждой страницы:
- сохраняет HTML;
- извлекает ресурсы и ссылки;
- скачивает ассеты и вложенные зависимости.
- Для CSS/JS/JSON выполняет дополнительный разбор на скрытые зависимости.
- Ссылки на страницы добавляются в очередь с учётом
max_depth. - По завершении формируется
download_report.jsonи печатается сводка.
Требования
- Python 3.10+ (рекомендуется).
- Зависимости из
requirements.txt:requestsbeautifulsoup4
Установка (Windows / PowerShell)
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
Установка (Linux/macOS)
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Использование downloader
Синтаксис
python .\website_downloader.py <URL> [output_dir] [max_depth] [max_pages] [--external] [--exclude-domain <domain>]
Параметры
URL— стартовый адрес сайта (обязательно).output_dir— каталог сохранения (по умолчанию:website_download).max_depth— максимальная глубина обхода HTML-ссылок (по умолчанию:5).max_pages— общий ограничитель на количество загруженных URL (по умолчанию:1000).--external— разрешает скачивать ассеты с внешних доменов.--exclude-domain <domain>— запрещает скачивание с указанного домена (можно повторять).
По умолчанию уже добавлен исключённый домен:
cdn.dribbble.com.
Примеры
# Минимальный запуск
python .\website_downloader.py https://example.com
# Папка + ограничение глубины/объёма
python .\website_downloader.py https://example.com my_site 3 500
# Разрешить внешние ассеты
python .\website_downloader.py https://example.com my_site 3 500 --external
# Разрешить внешние ассеты, но отключить конкретные домены
python .\website_downloader.py https://example.com my_site 3 500 --external --exclude-domain cdn.dribbble.com --exclude-domain fonts.example.com
Использование локального сервера
Синтаксис
python .\serve_site.py <URL-or-folder>
Что можно передать
- URL сайта (папка будет определена по
netloc), напримерhttps://www.example.com/; - имя папки рядом со скриптом, например
example.com; - абсолютный путь к каталогу сайта.
Примеры
python .\serve_site.py https://www.example.com/
python .\serve_site.py example.com
python .\serve_site.py D:\PROJECTS\@NEW\DFWebsite_Downloader\my_site
После запуска откройте:
http://127.0.0.1:8080/
Остановка сервера: Ctrl + C.
Docker (опционально)
В проекте есть docker-compose.yml с nginx, который раздаёт каталог ./site на порту 8080.
docker compose up -d
Важно: downloader по умолчанию сохраняет в website_download, поэтому для Docker-раздачи:
- либо запускайте downloader с
output_dir=site, - либо скорректируйте volume в
docker-compose.yml.
Структура результата
После скачивания в каталоге output_dir обычно появляются:
- HTML-страницы (
index.html,about.html,work/...); - ассеты (
css,js,images,fonts,external/...); download_report.json— итоговый отчёт.
В корне проекта создаётся лог:
downloader.log
Формат download_report.json
Ключевые поля отчёта:
start_url,domain,output_dir,timestamp;total_downloaded,total_failed;resources(разбивка наpages,styles,scripts,images,fonts,other);skipped_external(что найдено, но пропущено политикой доменов);external_iframes(внешние iframe, не включённые в обход).
Ограничения
Полная «бит-в-бит» копия сайта не всегда возможна только HTTP-скрапером. Проблемные случаи:
- SPA-маршрутизация и контент, рендерящийся только в браузере после выполнения JS;
- страницы и API за авторизацией;
- динамические URL, вычисляемые в runtime и не присутствующие в исходниках;
- антибот-защита, rate limit, гео/региональные ограничения.
Для таких случаев нужен отдельный браузерный режим (например, Playwright) с перехватом сетевых запросов.
Типовые проблемы и решения
1) 404 на файлы с ?v=...
Решено через схему __q_<hash> в downloader + соответствующий fallback в serve_site.py.
2) Не хватает ресурсов, которых нет в HTML
В проекте уже есть разбор CSS/JS/JSON, но при сложной runtime-логике часть зависимостей может не обнаружиться без браузерного выполнения JS.
3) Внешние ресурсы не скачиваются
Проверьте:
- добавлен ли флаг
--external; - не попадает ли домен под
--exclude-domain.
Файлы проекта
website_downloader.py— основной downloader.serve_site.py— локальный HTTP-сервер для скачанного сайта.requirements.txt— Python-зависимости.docker-compose.yml— опциональная раздача через nginx.LICENSE— лицензионные условия.
Быстрый старт
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
python .\website_downloader.py https://example.com site 4 800 --external
python .\serve_site.py site