Files
go-crawler/README.md

10 KiB
Raw Blame History

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 не перезатирали друг друга.
  • Опциональная «починка» ссылок: абсолютные ссылки на разрешённые домены переписываются в относительные, чтобы зеркало открывалось локально.
  • Принудительный UTF8 meta charset: чтобы уменьшить проблемы с кодировкой в сохранённых HTML.
  • Корректное завершение по Ctrl+C.

Требования

  • Go 1.21+
  • Установленный Chrome/Chromium (используется chromedp)

Быстрый старт

go mod tidy

# Запуск без сборки
go run .

# Или сборка
go build -o crawler.exe .
./crawler.exe

После запуска в консоли будет прогресс вида [crawled] ... и итоговая статистика (pages/assets/links fixed/time).

Конфигурация

Вся конфигурация сейчас задаётся константами в начале файла crawl.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] ....

Лицензия

Лицензия в репозитории не указана.