Добавлена начальная реализация Go Crawler с файлом README и конфигурацией.
This commit is contained in:
@@ -1,2 +1,131 @@
|
||||
# go-crawler
|
||||
# Go Crawler — быстрый краулер/зеркалатор сайта на Go
|
||||
|
||||
Проект делает локальную «зеркальную» копию сайта: обходит страницы, сохраняет HTML на диск и параллельно скачивает ассеты (CSS/JS/картинки/шрифты и т. п.). Для рендеринга страниц используется headless Chrome через `chromedp`, поэтому краулер подходит для сайтов, где контент появляется после выполнения JavaScript.
|
||||
|
||||
> Важно: используйте краулер только на сайтах, которые вы имеете право скачивать и архивировать. Учитывайте правила сайта и его ограничения (включая robots.txt и rate limits). Авторизация/капчи/антибот в проекте не реализованы.
|
||||
|
||||
## Основные возможности
|
||||
|
||||
- **Параллельный обход страниц**: несколько воркеров, каждый со своим экземпляром браузера.
|
||||
- **Параллельная загрузка ассетов**: отдельные HTTP-воркеры скачивают ресурсы быстрее, чем через браузер.
|
||||
- **Ограничение по доменам**: скачиваются только URL из `ALLOWED_ORIGINS`.
|
||||
- **Нормализация URL**: убирается `#fragment`, приводятся относительные ссылки к абсолютным, удаляется хвостовой `/` (кроме корня) — это уменьшает дубли.
|
||||
- **Дедупликация**: страницы и ассеты не обрабатываются повторно.
|
||||
- **Сохранение на диск в структуру, похожую на URL**:
|
||||
- директории превращаются в `index.html` (например, `/docs/` → `/docs/index.html`),
|
||||
- query-параметры хешируются и добавляются к имени файла, чтобы разные варианты URL не перезатирали друг друга.
|
||||
- **Опциональная «починка» ссылок**: абсолютные ссылки на разрешённые домены переписываются в относительные, чтобы зеркало открывалось локально.
|
||||
- **Принудительный UTF‑8 meta charset**: чтобы уменьшить проблемы с кодировкой в сохранённых HTML.
|
||||
- **Корректное завершение** по `Ctrl+C`.
|
||||
|
||||
## Требования
|
||||
|
||||
- Go 1.21+
|
||||
- Установленный Chrome/Chromium (используется `chromedp`)
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
```bash
|
||||
go mod tidy
|
||||
|
||||
# Запуск без сборки
|
||||
go run .
|
||||
|
||||
# Или сборка
|
||||
go build -o crawler.exe .
|
||||
./crawler.exe
|
||||
```
|
||||
|
||||
После запуска в консоли будет прогресс вида `[crawled] ...` и итоговая статистика (pages/assets/links fixed/time).
|
||||
|
||||
## Конфигурация
|
||||
|
||||
Вся конфигурация сейчас задаётся константами в начале файла `crawl.go`.
|
||||
|
||||
Ключевые параметры:
|
||||
|
||||
```go
|
||||
const (
|
||||
BASE_URL = "https://rutracker.org/forum/" // Стартовая точка обхода
|
||||
OUT_DIR = "rutracker.org" // Папка, куда сохраняется зеркало
|
||||
MAX_PAGES = 50000 // Лимит страниц (защита от бесконечного обхода)
|
||||
WORKERS = 10 // Кол-во браузеров (воркеров страниц)
|
||||
ASSET_WORKERS = 20 // Кол-во HTTP-воркеров для ассетов
|
||||
WAIT_AFTER_LOAD = 2 * time.Second // Пауза после Navigate для прогрузки JS
|
||||
REQUEST_TIMEOUT = 30 * time.Second // Таймаут навигации
|
||||
FIX_LINKS = true // Переписывать ссылки на относительные
|
||||
)
|
||||
|
||||
var ALLOWED_ORIGINS = []string{
|
||||
"https://rutracker.org",
|
||||
"https://www.rutracker.org",
|
||||
}
|
||||
```
|
||||
|
||||
### Как подобрать `ALLOWED_ORIGINS`
|
||||
|
||||
Если сайт грузит ресурсы с CDN/поддоменов, их нужно добавить в `ALLOWED_ORIGINS`, иначе ассеты и ссылки на них будут пропускаться.
|
||||
|
||||
### Тюнинг производительности
|
||||
|
||||
- Увеличивайте `WORKERS`, если упираетесь в скорость рендеринга страниц (но возрастут CPU/RAM).
|
||||
- Увеличивайте `ASSET_WORKERS`, если узкое место — скачивание ассетов.
|
||||
- `WAIT_AFTER_LOAD` критичен для SPA/React/Vue сайтов: слишком маленькое значение даст «пустые» HTML.
|
||||
|
||||
## Как это работает (в общих чертах)
|
||||
|
||||
1. В `pageQueue` кладётся нормализованный `BASE_URL`.
|
||||
2. `WORKERS` воркеров берут URL страницы, открывают новую вкладку, делают `Navigate`, ждут `WAIT_AFTER_LOAD`, сохраняют `OuterHTML`.
|
||||
3. Во время загрузки страницы подписка на `network` события собирает URL ресурсов; «не‑страницы» отправляются в `assetQueue`.
|
||||
4. HTML парсится регулярками, извлекаются ссылки (`href`, `src`, `data-src`, а также некоторые JSON‑поля вроде `"url"`, `"pathname"`).
|
||||
5. Если включён `FIX_LINKS`, ссылки на разрешённые домены переписываются в относительные пути на локальные файлы.
|
||||
6. HTML и ассеты сохраняются в `OUT_DIR` по схеме URL→путь.
|
||||
|
||||
## Что считается страницей, а что ассетом
|
||||
|
||||
Функция `isPageURL()` относит URL к ассетам по расширению (например, `.js`, `.css`, изображения, шрифты, видео/аудио, `.json`, `.xml`, `.pdf`, архивы). Всё остальное считается страницей и идёт в очередь обхода.
|
||||
|
||||
## Архитектура
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ main() │
|
||||
│ │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │Worker 1 │ │Worker 2 │ │Worker 3 │ │ ... │ × WORKERS
|
||||
│ │(Browser)│ │(Browser)│ │(Browser)│ │(Browser)│ │
|
||||
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
|
||||
│ │ │ │ │ │
|
||||
│ └────────────┴─────┬──────┴────────────┘ │
|
||||
│ │ │
|
||||
│ pageQueue (chan string) │
|
||||
│ │ │
|
||||
│ ┌──────────────────┴──────────────────┐ │
|
||||
│ │ │ │
|
||||
│ ┌────┴────┐ ┌─────────┐ ┌─────────┐ ┌───┴───┐ │
|
||||
│ │Asset W1 │ │Asset W2 │ │Asset W3 │ │ ... │ × ASSET_WORKERS
|
||||
│ │ (HTTP) │ │ (HTTP) │ │ (HTTP) │ │ (HTTP)│ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ └───────┘ │
|
||||
│ │ │
|
||||
│ assetQueue (chan AssetRequest) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Ограничения и нюансы
|
||||
|
||||
- **Robots/лимиты**: проект не читает `robots.txt` и не ограничивает частоту запросов тонко. Для «бережного» обхода уменьшайте `WORKERS`/`ASSET_WORKERS` и/или добавляйте задержки (пока это только `WAIT_AFTER_LOAD`).
|
||||
- **Авторизация и сессии**: нет логина, cookie‑менеджмента, обхода капч/антибота.
|
||||
- **Полнота зеркала**: ссылки извлекаются регулярками и сетью браузера; динамически генерируемые URL могут быть пропущены.
|
||||
- **Очень большие сайты**: `MAX_PAGES` — обязательная страховка. Также очереди и карты дедупликации держатся в памяти.
|
||||
- **Шумный вывод**: есть отладочные строки `[debug] Found ...`, а также `[skip-external]`/`[skip-asset]` — при необходимости их можно убрать/загейтить флагом.
|
||||
|
||||
## Типичный сценарий использования
|
||||
|
||||
1. Задайте `BASE_URL` и `OUT_DIR`.
|
||||
2. Заполните `ALLOWED_ORIGINS` (включая поддомены/CDN, если они нужны).
|
||||
3. Настройте параллельность (`WORKERS`, `ASSET_WORKERS`) и тайминги (`WAIT_AFTER_LOAD`, `REQUEST_TIMEOUT`).
|
||||
4. Запустите `go run .` и дождитесь `[done] ...`.
|
||||
|
||||
## Лицензия
|
||||
|
||||
Лицензия в репозитории не указана.
|
||||
|
||||
Reference in New Issue
Block a user