# 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/путей с докачкой ссылок. - Поддержка cache-busting query (`?v=...`, `?t=...`): - локальное имя файла получает суффикс `__q_`; - это предотвращает коллизии и помогает корректно раздавать такие файлы локально. - Дополнительная обработка популярных паттернов: - `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_.css` - fallback на уже сохранённые варианты `__q_*` даже при запросе без query. ## Как это работает 1. Скрипт начинает со стартового URL и формирует очередь страниц. 2. Для каждой страницы: - сохраняет HTML; - извлекает ресурсы и ссылки; - скачивает ассеты и вложенные зависимости. 3. Для CSS/JS/JSON выполняет дополнительный разбор на скрытые зависимости. 4. Ссылки на страницы добавляются в очередь с учётом `max_depth`. 5. По завершении формируется `download_report.json` и печатается сводка. ## Требования - Python 3.10+ (рекомендуется). - Зависимости из `requirements.txt`: - `requests` - `beautifulsoup4` ## Установка (Windows / PowerShell) ```powershell python -m venv .venv .\.venv\Scripts\Activate.ps1 pip install -r requirements.txt ``` ## Установка (Linux/macOS) ```bash python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` ## Использование downloader ### Синтаксис ```powershell python .\website_downloader.py [output_dir] [max_depth] [max_pages] [--external] [--exclude-domain ] ``` ### Параметры - `URL` — стартовый адрес сайта (обязательно). - `output_dir` — каталог сохранения (по умолчанию: `website_download`). - `max_depth` — максимальная глубина обхода HTML-ссылок (по умолчанию: `5`). - `max_pages` — общий ограничитель на количество загруженных URL (по умолчанию: `1000`). - `--external` — разрешает скачивать ассеты с внешних доменов. - `--exclude-domain ` — запрещает скачивание с указанного домена (можно повторять). > По умолчанию уже добавлен исключённый домен: `cdn.dribbble.com`. ### Примеры ```powershell # Минимальный запуск 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 ``` ## Использование локального сервера ### Синтаксис ```powershell python .\serve_site.py ``` ### Что можно передать - URL сайта (папка будет определена по `netloc`), например `https://www.example.com/`; - имя папки рядом со скриптом, например `example.com`; - абсолютный путь к каталогу сайта. ### Примеры ```powershell 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`. ```powershell 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_` в 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` — лицензионные условия. ## Быстрый старт ```powershell 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 ```