- Создан файл `fix-links.js` для обработки загрузки внешних ресурсов и исправления ссылок в HTML-файлах. - Добавлена конфигурация для разрешенных и пропускаемых доменов, настроек загрузки и механизмов кэширования. - Реализованы функции для обработки файлов, обработки URL-адресов и одновременных загрузок. - Введено отслеживание статистики для обработанных файлов, исправленных ссылок и сбоев загрузки. Задача: инициализация package.json и package-lock.json - Добавлен файл `package.json` с метаданными проекта и зависимостями. - Создан файл `package-lock.json` для блокировки версий зависимостей для обеспечения согласованной установки.
216 lines
9.8 KiB
Markdown
216 lines
9.8 KiB
Markdown
# mirror-forge
|
||
|
||
Node.js-проект для зеркалирования сайта в локальную папку `mirror/` с помощью Playwright (headless Chromium).
|
||
|
||
Проект включает два сценария:
|
||
|
||
1. `crawl.js` — обходит страницы сайта, сохраняет HTML и ресурсы (CSS/JS/изображения/шрифты и т.д.).
|
||
2. `fix-links.js` — пост-обработка уже скачанного зеркала: ищет внешние URL в HTML, догружает недостающие файлы и заменяет ссылки на локальные относительные пути.
|
||
|
||
---
|
||
|
||
## Возможности
|
||
|
||
- Обход внутренних страниц с очередью URL и ограничением по количеству страниц.
|
||
- Параллельная загрузка (`CONCURRENCY`) для ускорения зеркалирования.
|
||
- Перехват `response` в браузере и сохранение ассетов по `Content-Type`.
|
||
- Автоповторы при ошибках (`MAX_RETRIES`).
|
||
- Извлечение новых ссылок из финального DOM страницы, а не только из сырого HTML.
|
||
- Корректное завершение по `Ctrl+C` (graceful shutdown).
|
||
- Нормализация путей для Windows (замена недопустимых символов).
|
||
- Поддержка query-строк через хеширование имени файла, чтобы избежать перезаписи.
|
||
- Опциональная замена абсолютных ссылок в HTML на относительные (`FIX_LINKS`).
|
||
- Принудительное сохранение HTML в UTF-8 (`<meta charset="utf-8">`).
|
||
|
||
---
|
||
|
||
## Стек и требования
|
||
|
||
- Node.js 18+
|
||
- npm
|
||
- Playwright (`playwright`)
|
||
- ОС: Windows / Linux / macOS
|
||
|
||
> В `package.json` проект работает в режиме ES Modules (`"type": "module"`).
|
||
|
||
---
|
||
|
||
## Установка
|
||
|
||
```bash
|
||
npm install
|
||
npx playwright install
|
||
```
|
||
|
||
Если зависимостей ещё нет, альтернативно:
|
||
|
||
```bash
|
||
npm i playwright
|
||
npx playwright install
|
||
```
|
||
|
||
---
|
||
|
||
## Быстрый старт
|
||
|
||
### 1) Скачивание сайта
|
||
|
||
```bash
|
||
node crawl.js
|
||
```
|
||
|
||
### 2) Дополнительная фиксация ссылок (опционально)
|
||
|
||
```bash
|
||
node fix-links.js
|
||
```
|
||
|
||
---
|
||
|
||
## Как устроен `crawl.js`
|
||
|
||
### Основной поток
|
||
|
||
1. В очередь добавляется `BASE`.
|
||
2. URL обрабатываются батчами по `CONCURRENCY`.
|
||
3. Для каждой страницы:
|
||
- выполняется `page.goto(..., waitUntil: "domcontentloaded")`;
|
||
- даётся дополнительная пауза `WAIT_AFTER_LOAD`;
|
||
- выполняется попытка дождаться `networkidle`;
|
||
- через `page.on("response")` сохраняются ассеты;
|
||
- HTML сохраняется в `mirror/`;
|
||
- извлекаются новые ссылки и добавляются в очередь.
|
||
4. При ошибках применяются автоповторы до `MAX_RETRIES`.
|
||
|
||
### Что скачивается
|
||
|
||
- HTML-документы.
|
||
- Скрипты, стили, изображения, шрифты.
|
||
- XHR/fetch-ответы (с ограничениями, см. ниже).
|
||
|
||
### Что фильтруется/ограничивается
|
||
|
||
- Обход ограничен разрешёнными URL-префиксами (`ALLOWED_URL_PREFIXES`) и origin, вычисленными из них.
|
||
- JSON-ответы без расширения `.json` пропускаются в загрузчике ассетов, чтобы не перезаписывать HTML.
|
||
- URL с неподдерживаемыми схемами (`data:`, `javascript:`, `mailto:`, `tel:`, `blob:`) игнорируются.
|
||
- Ассеты (по расширению) не попадают в очередь страниц.
|
||
|
||
---
|
||
|
||
## Конфигурация `crawl.js`
|
||
|
||
Ключевые параметры находятся вверху файла:
|
||
|
||
- `BASE` — стартовый URL обхода.
|
||
- `OUT_DIR` — папка вывода (по умолчанию `mirror`).
|
||
- `MAX_PAGES` — лимит страниц для обхода.
|
||
- `CONCURRENCY` — количество одновременно открытых вкладок.
|
||
- `WAIT_AFTER_LOAD` — задержка после `domcontentloaded`.
|
||
- `MAX_RETRIES` — число повторных попыток для страницы.
|
||
- `REQUEST_TIMEOUT` — таймаут навигации `page.goto`.
|
||
- `USER_AGENT` — User-Agent браузера.
|
||
- `FIX_LINKS` — включить замену ссылок в HTML на относительные в момент сохранения.
|
||
- `ALLOWED_URL_PREFIXES` — список URL-префиксов, которые разрешено обходить/скачивать.
|
||
|
||
---
|
||
|
||
## Как формируются локальные пути
|
||
|
||
- URL-path сохраняется как путь внутри `mirror/`.
|
||
- Путь, заканчивающийся на `/`, сохраняется как `.../index.html` (через `index` + расширение).
|
||
- Query-строка хешируется (`md5`, 8 символов) и добавляется к имени файла.
|
||
- Если у URL нет расширения, оно определяется по `Content-Type`; если определить нельзя — используется `.html`.
|
||
- Символы, недопустимые в Windows-путях, заменяются на `_`.
|
||
|
||
---
|
||
|
||
## Как устроен `fix-links.js`
|
||
|
||
`fix-links.js` предназначен для пост-обработки уже скачанного зеркала.
|
||
|
||
Что делает скрипт:
|
||
|
||
1. Рекурсивно находит HTML/HTM-файлы в `mirror/`.
|
||
2. Извлекает URL из `src/href/srcset/poster/data-src/url(...)`.
|
||
3. Для внешних и отсутствующих относительных ссылок:
|
||
- проверяет домены по правилам `ALLOWED_DOMAINS` и `SKIP_DOMAINS`;
|
||
- скачивает ресурсы в локальную структуру с ограничением по конкурентности;
|
||
- заменяет абсолютные ссылки на относительные пути.
|
||
4. Ведёт статистику: обработано файлов, исправлено ссылок, скачано/пропущено/ошибки.
|
||
|
||
Ключевые параметры в `fix-links.js`:
|
||
|
||
- `MIRROR_DIR` — папка зеркала.
|
||
- `DOWNLOAD_TIMEOUT` — таймаут загрузки одного ресурса.
|
||
- `DOWNLOAD_CONCURRENCY` — число одновременных загрузок при пост-обработке.
|
||
- `MAX_RETRIES` — число повторов загрузки.
|
||
- `ALLOWED_DOMAINS` — явно разрешённые домены для скачивания.
|
||
- `SKIP_DOMAINS` — домены, которые нужно пропускать.
|
||
|
||
---
|
||
|
||
## Логи и статус
|
||
|
||
### `crawl.js`
|
||
|
||
- `[start]` — старт обхода.
|
||
- `[config]` — активные параметры.
|
||
- `[crawled]` — страница сохранена.
|
||
- `[retry x/y]` — повторная попытка.
|
||
- `[gave up]` — страница не скачана после всех повторов.
|
||
- `[done]` — итоговая статистика.
|
||
|
||
### `fix-links.js`
|
||
|
||
- `📄 Обрабатываю` — файл в обработке.
|
||
- `📥 Скачиваю` / `✅ Скачано` / `❌ Не удалось скачать`.
|
||
- При неудачной загрузке исходная ссылка сохраняется, чтобы не превращать рабочий внешний URL в битый локальный путь.
|
||
- Итоговый блок `📊 СТАТИСТИКА`.
|
||
|
||
---
|
||
|
||
## Ограничения
|
||
|
||
- Это не «пиксель-в-пиксель офлайн-клон» сложных SPA/PWA.
|
||
- Контент, подгружаемый только после действий пользователя (скролл/клик/hover), может не попасть в зеркало.
|
||
- Внешние сервисы аналитики/соцсети/CDN могут оставаться внешними ссылками (зависит от доменных правил).
|
||
- API-данные с динамическими эндпоинтами не гарантируется получить полностью.
|
||
|
||
---
|
||
|
||
## Рекомендации по эксплуатации
|
||
|
||
- Начинайте с меньшего `MAX_PAGES` и `CONCURRENCY`, затем увеличивайте.
|
||
- При частых таймаутах увеличьте `REQUEST_TIMEOUT` и/или `WAIT_AFTER_LOAD`.
|
||
- Если сервер ограничивает запросы, уменьшите `CONCURRENCY`.
|
||
- Перед массовым запуском проверьте политики сайта (`robots.txt`, Terms of Service) и правовые ограничения.
|
||
|
||
---
|
||
|
||
## Типичный workflow
|
||
|
||
1. Настроить `BASE` и `ALLOWED_URL_PREFIXES` в `crawl.js`.
|
||
2. Запустить `node crawl.js`.
|
||
3. Проверить структуру `mirror/`.
|
||
4. При необходимости запустить `node fix-links.js`.
|
||
5. Открывать локальные HTML из `mirror/` для анализа/архивации/офлайн-просмотра.
|
||
|
||
---
|
||
|
||
## Структура проекта
|
||
|
||
```text
|
||
.
|
||
├─ crawl.js
|
||
├─ fix-links.js
|
||
├─ package.json
|
||
├─ README.md
|
||
└─ mirror/ # создаётся после запуска
|
||
```
|
||
|
||
---
|
||
|
||
## Лицензия
|
||
|
||
ISC (см. `package.json` и `LICENSE`).
|