84 зірок на GitHub, і їхня кількість продовжує зростати. Yozh Crawler + Scraper — це безкоштовний проект з відкритим кодом, який розробляється відкрито. Поставте нам зірку, якщо він заслуговує на місце у вашому стеку.
CyberYozh Data / Yozh Crawler
Програмне забезпечення · Yozh Crawler

Введіть лише одну URL-адресу, і весь сайт завантажиться

Yozh Crawler сканує сайт, починаючи з одного URL-адреси, і передає кожну виявлену сторінку через SSE. Він бере на себе найскладніші аспекти сканування — пошук нових ресурсів, усунення дублікатів, визначення обсягу, дотримання правил етикету та повторні спроби, — тоді як завантаження кожної сторінки здійснюється через Yozh Scraper. Без дублювання Playwright, без SaaS, працює на :8001.

$curl -N :8001/api/v1/crawl -d '{"seed_url":"https://site.com", "scope":{"mode":"same-domain","max_depth":2,"max_pages":500}}'

Обхід

Yozh Crawler обходить сайт, починаючи з одного вихідного URL-адреси, і передає кожну виявлену сторінку через SSE. Він відповідає за процес виявлення — визначення меж, дедуплікацію, визначення області пошуку, вилучення посилань, повторні спроби та дотримання правил ввічливості — тоді як завантаження кожної сторінки делегується Yozh Scraper через HTTP. Для роботи використовується лише один стек Playwright, і всі функції скрепера (проксі, прихований режим, сесії, правила вилучення даних) застосовуються також і до проіндексованих сторінок.

  • Предикати області діїsame-domain / subdomains / all / regex, з шаблонами включення та виключення та жорсткими max_depth / max_pages обмеженнями.
  • Дедуплікація за «відбитками» — URL-адреси канонізуються, а потім хешуються (SHA1), завдяки чому запити з іншою послідовністю та варіанти з кінцевим слешем об’єднуються в одне відвідування.
  • Принцип «round-robin» на рівні домену — один повільний або величезний хост не може позбавити інших робочих процесів.
  • Адаптивний обмежувач швидкості — глобальний «кошик токенів» (з джиттером) для кожного домену, спільний для всіх завдань; це 429 зменшує RPS удвічі на час періоду охолодження.
  • Стан сеансу — система оцінювання за методом Crawlee: 401/403/429 завершення сеансу, помилки підвищують його оцінку, успішні дії — знижують; ротація відбувається при оцінці ≥ 3 або після 50 використань.
  • Потокове передавання SSE — кожне завдання генерує stats, page, page_error, а також події done / cancelled . Реагуйте на знайдені дані одразу ж після їх надходження.
Базова URL-адресаhttp://localhost:8001
Документація OpenAPIhttp://localhost:8001/docs
Кінцева точка MCPhttp://localhost:8001/mcp
Супутня служба. Програма-сканер делегує кожне запитування програмі Yozh Scraper, тому запустіть обидві програми одночасно — скрейпер на :8000 , а сканер — на :8001.

Швидкий старт

Краулер підключений до кореня docker-compose.yml і запускається разом зі скрейпером:

bash
docker compose up --build
# scraper  → http://localhost:8000
# crawler  → http://localhost:8001

Або запустіть його локально без Docker — вкажіть SCRAPER_URL на запущений скрейпер:

bash
cd yozh-crawler
pip install -r requirements.txt
cp .env.example .env          # edit SCRAPER_URL if needed
python -m uvicorn src.main:app --reload --port 8001

Основні принципи використання

Надіслати запит на сканування з seed_url та scope. Виклик негайно повертає job_id ; після цього сканування виконується у фоновому режимі за допомогою робочих завдань.

cURL
curl -X POST http://localhost:8001/api/v1/crawl 
  -H "Content-Type: application/json" 
  -d '{
    "seed_url": "https://example.com",
    "scope": {"mode": "same-domain", "max_depth": 2, "max_pages": 50,
              "per_domain_rps": 1.0, "per_domain_concurrency": 1},
    "scrape_options": {"proxy_type": "none"},
    "enable_scraping": false
  }'

Відповідь — це лише ідентифікатор завдання:

JSON
{ "job_id": "crawl_abc123" }

Звідси ви можете або дивитися прямі трансляції подій, або завантажити повний запис.

«Відкриття» проти «збору» — enable_scraping перемикач

Один і той самий механізм сканування працює в обох напрямках. Один логічний оператор визначає вибір між «економічним» скануванням для створення карти та повним збором даних — і кожен режим використовує власну конфігурацію проксі-сервера, тому взаємовплив між ними відсутній.

enable_scraping: false

Карта відкриттів

Поверхневий обхід. Скрейпер як і раніше обробляє кожну сторінку (тож посилання, створені за допомогою JS, виявляються), але сканер зберігає лише основну структуру — це ідеально підходить для створення карт сайту, аудиту посилань та виявлення змін.

  • Зберігає url · parent_url · depth · status · took_ms
  • Додає необроблений HTML-код, скріншоти та витягнуті дані
  • Використовує дешевший crawl_proxy
  • Найменші корисні навантаження, найшвидше сканування
enable_scraping: true

Повний збір

Кожна відвідана сторінка зберігається разом із повним ScrapeResponse — вихідним HTML-кодом, опціональним знімком екрана та будь-якими полями з ваших правил вилучення. Сканування та структурування за один прохід.

  • Зберігає повний ScrapeResponse на сторінці
  • raw_html · screenshot · витягнуто data
  • Застосування scrape_options.proxy_*
  • Перейти extract правила для отримання чистого JSON
Вибір проксі-сервера. crawl_proxy використовується лише тоді, коли enable_scraping=false; scrape_options.proxy_* використовується, коли true. Якщо crawl_proxy є null, то scrape_options проксі використовується незалежно від режиму.

Обсяг індексації

Область дії визначає межі сканування: де дозволено переміщатися та наскільки інтенсивно можна завантажувати кожен хост. Це scope об’єкт у запиті.

ПолеТипЗа замовчуваннямОпис
modesame-domain · subdomains · all · regexsame-domainЯкі посилання входять до сфери застосування. regex відповідає include_patterns.
include_patternsstring[][]Регулярні вирази, яким повинен відповідати URL-адреса для включення в чергу (використовується в regex режимом / як список дозволених адрес).
exclude_patternsstring[][]Регулярні вирази, які виключають URL-адресу, навіть якщо вона в іншому випадку потрапляє в область дії.
max_depthint3Максимальна глибина зв’язку від початкового вузла (початковий вузол має глибину 0).
max_pagesint500Максимальна кількість сторінок, які можна відвідати до завершення сканування.
per_domain_rpsfloat1.0Швидкість поповнення «кошика токенів» для кожного домену (запити/секунду).
per_domain_concurrencyint1Максимальна кількість запитів під час сеансу до одного домену.
Наївна область дії subdomains. Вона використовує останні дві мітки як домен, що підлягає реєстрації, тому відбувається надмірне співпадіння з хостами зі списку публічних суфіксів, такими як github.io або co.uk. Краще використовувати same-domain або regex для таких випадків.

Результати потокової передачі (SSE)

Кожне завдання надає доступ до потоку Server-Sent Events. Використовуйте його, щоб обробляти сторінки одразу після їх виявлення, замість того щоб чекати завершення сканування.

cURL
curl -N http://localhost:8001/api/v1/crawl/crawl_abc123/events

Потік генерує п’ять типів подій:

ПодіяКоли
statsПеріодичний знімок стану виконання (відвідано / у черзі / невдало / пропущено через дублювання / поза межами сфери застосування / повторні спроби).
pageОдин запис на кожну відвідану URL-адресу. Містить повні ScrapeResponse у режимі збору даних, скорочені метадані — у режимі пошуку.
page_errorURL-адреса, для якої всі спроби підключення завершилися невдачею.
doneТермінал — сканування завершилося успішно.
cancelledТермінал — сканування було скасовано.

Подія page подія в режимі виявлення виглядає так:

JSON
{
  "event": "page",
  "url": "https://example.com/docs/intro",
  "parent_url": "https://example.com/docs",
  "depth": 2,
  "status_code": 200,
  "took_ms": 812,
  "scrape_response": null
}

Стан та результати

Віддаєте перевагу опитуванню? Запис про завдання можна переглянути в будь-який момент — у тому числі під час сканування, з урахуванням сторінок, виявлених на цей момент. /results є псевдонімом кінцевої точки завдання, який збережено для симетрії зі скрепером.

cURL
curl http://localhost:8001/api/v1/crawl/crawl_abc123
curl http://localhost:8001/api/v1/crawl/crawl_abc123/results
JSON
{
  "job_id": "crawl_abc123",
  "status": "running",
  "stats": {
    "visited": 47, "queued": 12, "failed": 0,
    "dedup_skipped": 9, "out_of_scope": 31, "retries_total": 2
  },
  "pages": [
    { "url": "https://example.com/", "parent_url": null,
      "depth": 0, "status_code": 200, "took_ms": 640 }
  ]
}
status проходить через queuedrunningdone (або failed / cancelled).

Скасування сканування

Зупиніть завдання, що виконується, за допомогою DELETE. М'яке скасування є стандартним варіантом і найбезпечнішим вибором.

cURL
# soft — stop scheduling, let in-flight requests drain
curl -X DELETE "http://localhost:8001/api/v1/crawl/crawl_abc123?hard=false"

# hard — abort in-flight asyncio tasks immediately
curl -X DELETE "http://localhost:8001/api/v1/crawl/crawl_abc123?hard=true"
Примусове скасування призводить до того, що скрейпер залишається «сиротою». A ?hard=true призводить до відміни поточного запиту сканера, але сам сканер не має можливості про це дізнатися — рендеринг сторінки завершується з його боку. Надавайте перевагу м'якому скасуванню, якщо тільки вам не потрібно зупинитися негайно.

MCP

fastapi-mcp встановлено за адресою /mcp як кінцева точка Streamable HTTP. Наведіть Claude або Cursor на неї, і інструменти з’являться автоматично:

  • health
  • create_crawl
  • get_crawl
  • get_crawl_results
  • cancel_crawl
~/.claude/settings.json
"open-crawler": {
  "type": "http",
  "url": "http://localhost:8001/mcp"
}
Ендпойнт SSE stream_crawl_events навмисно виключено з MCP — потокові відповіді не сумісні з інструментом типу «запит/відповідь».

Довідник з налаштування

Запит — CrawlRequest

ПолеТипЗа замовчуваннямОпис
seed_urlрядок (URL)обов’язковеЄдиний URL-адресу, з якої починається сканування.
scopeCrawlScopedefaultsМежі та ввічливість — див. «Область дії сканування».
scrape_optionsScrapeOptionsdefaultsПередається дослівно до скрепера по сторінці (url вставляється).
crawl_proxyScrapeOptions · nullnullДешевий проксі, що використовується в режимі виявлення. Читаються лише proxy_type / proxy_pool_id / proxy_geo зчитуються.
enable_scrapingboolfalseВкажіть повну кількість ScrapeResponse на кожній сторінці (true) або лише метадані пошуку (false).

За сторінку — ScrapeOptions (вибрано)

ПолеТипЗа замовчуваннямОпис
proxy_typenone · mobile · res_static · res_rotating · dc_static · …noneПул проксі-серверів, через який здійснюється завантаження сторінок.
devicedesktop · mobiledesktopВікно перегляду / профіль UA.
renderbooltrueВідобразити за допомогою браузера (необхідно для посилань, створених за допомогою JS).
stealthbooltrueЗастосуйте заходи з посилення захисту від виявлення.
wait_untildomcontentloaded · networkidledomcontentloadedКоли сторінка вважається готовою.
screenshotboolfalseЗробити знімок екрана (режим «збору»).
extractExtractRule · nullnullПравила для полів CSS/XPath → структуровані data на кожній сторінці.
session_idрядок · nullnullПовторне використання сеансу скрепера з автентифікацією — див. розділ «Скрейпінг з автентифікацією».

Змінні середовища

ЗміннаЗа замовчуваннямПримітки
SCRAPER_URLhttp://web-scraper:8000Скрепер на вході (використовуйте ім’я служби Docker у мережі Compose).
WORKERS2Кількість паралельних завдань індексації.
QUEUE_MAXSIZE200Глибина черги завдань, що очікують на виконання.
JOB_TIMEOUT_MS3_600_000Обмеження тривалості одного завдання, що виконується у фоновому режимі, у вигляді «стінного годинника».
SCRAPER_JOB_TIMEOUT_MS120_000Тайм-аут запиту скрепера на одну сторінку.
MAX_RETRIES3Кількість повторних спроб на один запит у разі тимчасової помилки.
RETRY_HTTP_CODES[408,429,500,502,503,504]Коди статусу, які викликають повторну спробу.
RETRY_BACKOFF_MAX30.0Верхня межа експоненціального відступу (секунди).
SESSION_MAX_ERROR_SCORE3.0Поріг завершення сеансу.
SESSION_MAX_USAGE50Оновити сесію після N використань.
SESSION_BLOCKED_CODES[401,403,429]Коди, які миттєво завершують сеанс.

Довідник API

МетодШляхПризначення
POST/api/v1/crawlСтворити завдання. Повертає {"job_id":"…"}.
GET/api/v1/crawl/{id}Запис про роботу — статус, статистика, кількість переглянутих сторінок.
GET/api/v1/crawl/{id}/resultsПсевдонім запису про вакансію.
GET/api/v1/crawl/{id}/eventsПотік SSE (stats/page/page_error/done/cancelled).
DELETE/api/v1/crawl/{id}?hard=boolСкасувати завдання (м’яке або жорстке скасування).
GET/api/v1/healthЗдоров’я + доступність скрепера.

Важливі деталі

Без аутентифікації (v1). Жоден кінцевий пункт не проходить аутентифікацію — ця функція призначена для внутрішніх або надійних мереж. Будь-хто, хто має доступ до нього, може надіслати запит POST із довільним початковим значенням і перетворити його на SSRF-проксі. Тримайте його всередині вашої VPC або за вашим власним шлюзом аутентифікації.
robots.txt не враховується. Пошуковий робот обходить усі URL-адреси, що входять до сфери дії, незалежно від /robots.txt. Ви несете відповідальність за дотримання правил файлу robots.txt та умов використання сайту щодо об’єктів, які вам не належать — використовуйте exclude_patterns та обмеження швидкості, щоб дотримуватися етикету.
Відсутність стійкості. Завдання зберігаються в пам’яті та скидаються під час перезапуску контейнера (аналогічно до скрепера). Для забезпечення стійкості даних передавайте потік SSE у власне сховище (файл, Postgres, Kafka) у міру надходження сторінок. Періодично перезапускайте довготривалі процеси — завершені завдання накопичуються у сховищі.
Сканування з авторизацією. Створіть сесію на скрепері (POST /sessions + POST /sessions/{id}/login), а потім передайте scrape_options.session_id. Скрейпер передає кукі та стан сховища в обох напрямках для кожного запиту, тому кожна просканована сторінка бачить стан з автентифікацією.
Приклад у дії

Той самий домен — безпечний варіант за замовчуванням

Залишайтеся на точному початковому хості, обмежуйте глибину та кількість сторінок, дотримуйтеся ввічливості. Режим виявлення (enable_scraping: false) зберігає лише каркас кожної сторінки.


            

Нас люблять data-команди та AI-розробники

Що кажуть люди, які створюють проекти за допомогою Yozh

5,0 / 5 · Огляд 5
GitHub
За одне післяобіддя ми замінили наш внутрішній кластер Playwright на Yozh. Кінцева точка MCP одразу ж інтегрувалася в наш агент Claude — жодного допоміжного коду, а сканер і скрепер просто запрацювали.
Marcus Reinhardt Головний інженер з обробки даних Northwind Analytics
X
Система пресетів — це головна фішка. Ми передаємо назву джерела й отримуємо у відповідь чистий JSON; функція автоматичного відновлення навіть встигла виявити дві зміни у макеті Amazon ще до того, як ми їх помітили.
Priya Nair Засновник ScrapeStack
Reddit
Нарешті з’явився скрейпер з відкритим кодом, який розглядає проксі-сервери та сесії як повноцінні компоненти. Ми використовуємо його для доступу до партнерських порталів, що вимагають авторизації — сесії зберігаються, а результати залишаються однаковими в усіх регіонах.
Daniel Osei Інженер бекенду Loopfeed
X
Підключив його до Cursor через MCP, і тепер мій агент отримує веб-дані в режимі реального часу під час виконання завдання. Потокове сканування через SSE — це саме те, чого бракувало робочим процесам агента.
Elena Kovac Інженер з штучного інтелекту Vektor Labs
GitHub
Ми відмовилися від платного API для зчитування даних, щоб скоротити витрати, і готувалися до погіршення якості — але отримали зовсім протилежний результат. Сервіс розміщений на власному хостингу, оплата не стягується за кожен запит, а схема вихідних даних є чіткішою, ніж та, за яку ми раніше платили.
Sofia Almeida Керівник інженерного відділу Tabbly
Відкрите програмне забезпечення · Ліцензія MIT · 84 ★

Вкажіть URL — і дивіться, як сторінки надходять у реальному часі

Yozh Crawler поставляється в тому самому репозиторії, що й скрейпер — один docker compose up — і ви отримуєте інструмент для пошуку та вилучення даних, готовий до роботи з MCP, на вашій власній інфраструктурі. Безкоштовно. Назавжди. Додайте нас до обраного, якщо цей інструмент заслужить своє місце у вашому стеку.

Yozh Crawler + Scraper розповсюджується за ліцензією MIT. Користуйтеся ним. Створюйте форки. Розробляйте на його основі.