Обзор модуляЧасть II · ~8 ч · Сложность: (средний) · Пререквизиты: Модуль 0, Модуль 1
Краулинг (crawling) — это первое звено офлайн-конвейера поисковой системы: пока документ не скачан и не передан дальше, его для поиска не существует. Этот модуль — Часть II темы обхода: мы считаем, что общий принцип «робот ходит по ссылкам и качает страницы» уже понятен (Модуль 0), и сосредотачиваемся на инженерии промышленного обхода — той, что отделяет учебный скрипт «скачай страницу по URL» от системы, обходящей десятки миллиардов документов годами без остановки.
Робот обхода (crawler, иногда «паук», spider) живёт под жёсткими ограничениями сразу с трёх сторон. Со стороны веба: URL почти бесконечно много, они появляются и умирают, среди них есть ловушки и спам. Со стороны хозяев сайтов: нельзя долбить чужой сервер с произвольной частотой, нужно уважать правила доступа и не выглядеть как DDoS. Со стороны самой поисковой системы: ресурсы (сеть, диск, процессор рендеринга) конечны, а значит обход — это всегда задача приоритизации под бюджетом: что скачать сейчас, что потом, а что не качать никогда.
В этом модуле мы разберём четыре блока. (1) Как робот узнаёт о новых URL и как устроен фронтир — структура, хранящая «что обойти дальше». (2) Как робот ведёт себя вежливо и как решает, когда вернуться на страницу снова (переобход, recrawl), вводя понятия ранга обхода и краулингового бюджета. (3) Как устроено управление доступом: протокол исключений для роботов, бан-листы, защита от ловушек и спама в каналах приёма URL. (4) Самое тяжёлое — скачивание и рендеринг JavaScript и потоковая постобработка скачанного контента.
После модуля студент сможет спроектировать фронтир с приоритизацией и политикой вежливости, объяснить, на что тратится краулинговый бюджет, отличить добросовестный URL от ловушки и оценить, почему рендеринг динамических страниц на порядок дороже скачивания статики. Инженер получит набор инвариантов для проектирования распределённого робота; SEO-специалист — рабочую модель того, что именно робот видит, чего не видит и как этим управлять (sitemap, доступность, дубли по параметрам, экономия бюджета).
Как читать по трекам
- Студент CS: главы 2.1 и 2.2 обязательны (фронтир, приоритизация, переобход — это про структуры данных и расписания). 2.3 — на понимание. 2.4 — обзорно, кроме модели «скачивание vs рендеринг».
- Инженер поиска/ML: весь модуль обязателен. Особое внимание — инвариантам распределённого фронтира (2.1), очередям вежливости (2.2), потоковой постобработке и пулу рендеринга (2.4).
- SEO-специалист: обязательны все SEO-врезки и главы 2.2 (краулинговый бюджет, переобход), 2.3 (robots, доступность), 2.4 (что видит робот без JS). Выводы про структуры данных можно обзорно.
- Смешанный/руководитель: «Обзор», по одной «Интуиции» из каждой главы, «Итоги модуля». Достаточно для картины «как и почему робот выбирает, что качать».
- 2.1. Обнаружение и приём URL, фронтир, очередь и приоритизация обхода (средний)
- 2.2. Политика вежливости, частота переобхода, ранги обхода, бюджет краулинга (средний)
- 2.3. Управление доступом: robots, бан-листы, краулерные ловушки, спам приёмки URL (средний)
- 2.4. Скачивание, рендеринг JavaScript, потоковая постобработка контента (продвинутый)
Цели обучения
После этой главы студент сможет:
- Перечислить и сравнить каналы обнаружения URL (ссылки, sitemap, прямая приёмка, переобход) и оценить их доверие.
- Объяснить, что такое фронтир (frontier) и какие инварианты он обязан держать (дедупликация, нормализация, разделение по хостам).
- Спроектировать двухуровневую очередь фронтира: приоритет «что» обходить × вежливость «когда» к данному хосту.
- Сравнить стратегии обхода (BFS, обход по приоритету, OPIC-подобное распределение «денег обхода») и обосновать выбор.
- Реализовать дедупликацию URL до загрузки и оценить её цену по памяти.
Робот обхода — это, по сути, бесконечный цикл: взять URL из фронтира → скачать → извлечь ссылки и метаданные → вернуть новые URL во фронтир. Вся сложность спрятана в словах «взять» и «вернуть»: в каком порядке брать и что именно возвращать.
Код: Выделить всё
┌──────────────── каналы обнаружения ────────────────┐
ссылки со sitemap прямая приёмка переобход
скачанных стр. (объявленные) (API/пинг/каналы) (по расписанию)
│ │ │ │
└───────────────┴───────┬──────────┴───────────────────┘
▼
┌──────────────────┐
│ приём URL │ нормализация · фильтрация ·
│ (URL ingestion) │ дедуп · оценка приоритета
└─────────┬─────────┘
▼
┌──────────────────┐
│ ФРОНТИР │ очередь «что» × очередь «когда»
│ (frontier) │
└─────────┬─────────┘
▼
воркеры-загрузчики → парсинг → новые URL ──┐
▲ │
└─────────────────────────────────┘
Откуда робот вообще узнаёт, что URL существует:
Код: Выделить всё
Канал | Источник | Доверие | Комментарий
----------------------------+-------------------------------------------+-------------------+---------------------------------------------
Ссылки (link extraction) | href/src со скачанных страниц | среднее | основной источник; даёт связность графа
Sitemap | объявленные сайтом файлы со списком URL | среднее-высокое | сайт сам подсказывает, что и когда обходить
Прямая приёмка (push/ping) | уведомления «у меня новый URL» | низкое-среднее | быстро, но открыто для спама (см. 2.3)
Переобход (recrawl) | планировщик: «пора освежить» | высокое | URL уже известен, обновляем копию
Внешние списки | реестры доменов, потоки новостей | разное | вспомогательно, для свежести (Модуль 17)
Интуиция. Фронтир — это «список дел» робота, который сам себя пополняет: почти каждая скачанная страница рождает новые пункты. Без жёсткой дисциплины приёма этот список взрывается экспоненциально и забивается мусором.
Нормализация URL до постановки в очередьSEO-врезка. Sitemap — это подсказка, а не команда. Он помогает роботу обнаружить URL (особенно «глубокие», на которые мало внутренних ссылок) и сообщает lastmod. Но sitemap не заставляет проиндексировать и не повышает ранг. Практика: держите в sitemap только канонические, доступные (200 OK, не закрытые в robots) URL; протухший sitemap с 404-ками подрывает доверие к каналу.
Прежде чем URL попадёт во фронтир, его нужно привести к канонической строковой форме — иначе одна и та же страница попадёт в очередь под десятком обличий. Нормализация (URL normalization) на этом этапе — синтаксическая, дешёвая (полная семантическая каноникализация документа — это Модуль 3):
- привести схему и хост к нижнему регистру: HTTP://Example.COM → http://example.com;
- убрать порт по умолчанию (:80 для http, :443 для https);
- декодировать лишнее процентное кодирование, нормализовать регистр escape-последовательностей;
- разрешить точки в пути: /a/./b/../c → /a/c;
- убрать #fragment (фрагмент не доходит до сервера);
- по политике — отсортировать или вырезать параметры запроса (осторожно! см. дубли по параметрам);
- убрать завершающий слэш по правилу хоста (рискованно — может менять смысл).
Что такое фронтир и его инвариантыВнимание. Нормализация — это компромисс. Слишком агрессивная (выкинули значимый параметр) — потеряли разные страницы. Слишком слабая — раздули фронтир дублями. На этапе приёма делают только безопасные преобразования; рискованные решения о тождестве откладывают на каноникализацию.
Фронтир (frontier) — структура данных, хранящая множество URL, которые робот намерен обойти, вместе с метаданными для приоритизации (оценка важности, время постановки, хост, дедуп-ключ). Промышленный фронтир обязан держать инварианты:
- Дедупликация. Один URL — одна запись. Иначе воркеры качают одно и то же.
- Нормализованность. Все ключи приведены к канонической форме (см. выше).
- Разделение по хостам. Для вежливости (2.2) URL одного хоста идут через общий «кран» частоты.
- Персистентность. Фронтир переживает перезапуск: миллиарды URL не помещаются в память, их хранят на диске/в распределённом хранилище, в памяти — только «горячая голова».
- Прогресс. Любой взятый URL либо скачан, либо возвращён с понижением (чтобы не зависал «в воздухе» при падении воркера).
Проверка «видели ли мы этот URL» делается до загрузки. Точное множество всех URL (их десятки миллиардов) в память не помещается. Решения:
- Хеш-множество на диске/в шардированном KV-хранилище — точно, но дорого по запросам.
- Фильтр Блума (Bloom filter) перед точной проверкой — компактный вероятностный фильтр: «точно не видели» или «возможно, видели». Ложноположительный ответ означает, что мы изредка пропустим действительно новый URL, зато память — биты на URL вместо десятков байт.
Приоритизация: очередь «что» × очередь «когда»Пример. Фильтр Блума на 10 млрд URL с долей ложноположительных ~1% требует ≈ 9.6 бит/элемент, то есть ≈ 12 ГБ — против сотен ГБ для хранения самих строк. Цена: ~1% новых URL будут ошибочно сочтены «уже виденными» и не попадут в обход. Для робота это приемлемо: такие URL почти наверняка придут снова по другой ссылке.
Главная идея промышленного фронтира — разделить два независимых вопроса:
- Что обходить первым (важность URL) — приоритетная сторона.
- Когда можно обратиться к данному хосту (вежливость) — временна́я сторона.
Код: Выделить всё
ВЕРХНИЙ уровень: F приоритетных очередей (по важности URL)
prio=1 [u u u] prio=2 [u u] prio=3 [u u u u] ...
│ маршрутизатор раскладывает URL по хостам ▼
НИЖНИЙ уровень: B очередей хостов (по одной на активный хост)
host_a [u u] host_b [u] host_c [u u u] ...
│ heap по «времени, когда хост снова свободен» ▼
┌─ min-heap (next_fetch_time) ─┐ → воркер берёт самый «созревший» хост
Стратегии порядка обхода
- BFS (поиск в ширину). Обход «по уровням» от стартовых URL. Прост, даёт неплохое покрытие, эмпирически рано находит важные страницы (важное обычно близко к корню). База по умолчанию.
- DFS (в глубину). Почти не используется: легко проваливается в бесконечную ветку (ловушка) и плохо распределяет нагрузку по хостам.
- Обход по приоритету. URL получает оценку важности (например, оценка ссылочной важности хоста/страницы, см. Модуль 7), очередь — приоритетная. Лучше тратит бюджет, но требует оценок до загрузки.
- OPIC-подобное распределение (On-line Page Importance Computation). Каждой странице выдают «наличность» (cash); при обходе она раздаёт свою наличность тем, на кого ссылается. URL с бо́льшим накопленным «доходом» обходят раньше. Даёт онлайновую оценку важности без отдельного офлайн-расчёта графа.
Инженерная заметка. Чистый приоритетный обход опасен «голоданием» (starvation): мелкие сайты с низкой оценкой могут не обойтись никогда. Лечится подмешиванием случайности/квот и «возрастом» URL (старый необойдённый URL постепенно поднимают в приоритете).
Частые заблужденияSEO-врезка. Доступность для робота. Чтобы страница попала во фронтир, на неё должна вести обнаружимая ссылка: обычный <a href> в HTML. Ссылки, появляющиеся только после клика/скролла через JS, или «ссылки» на javascript: робот по умолчанию не кладёт в очередь. Глубина клика тоже важна: страница в 6 переходах от главной обходится реже, чем в 1–2. Плоская архитектура и перелинковка — это буквально «помощь фронтиру».
Заблуждение. «Робот обходит весь сайт за один заход, сверху вниз.» Нет. URL сайта раскиданы по фронтиру среди миллиардов других, обход разорван во времени и перемешан между хостами ради вежливости и приоритета. Две страницы одного сайта могут быть скачаны с разницей в недели.
Лаба / практикаЗаблуждение. «Если я положил URL в sitemap, он гарантированно попадёт в очередь и будет скачан.» Sitemap — лишь канал обнаружения со средним доверием. URL всё равно проходит нормализацию, дедуп, фильтры доступа и приоритизацию под бюджетом.
Мини-фронтир с двухуровневой очередью. ~50 мин.
Дано: список из ~200 URL (несколько хостов), у каждого — оценка важности prio ∈ {1..5}. Параметр вежливости: к одному хосту не чаще, чем раз в 2 c.
Шаги (псевдокод/Python):
- Реализуйте normalize(url) (нижний регистр схемы/хоста, срез #fragment, удаление :80/:443).
- Дедуп через множество нормализованных URL (для учебного объёма — обычный set; отдельно прикиньте размер фильтра Блума на 10⁹ URL при p=1%).
- Верхний уровень: словарь prio -> deque. Нижний: на каждый хост — deque и поле next_time; общий min-heap по next_time.
- Цикл fetch: берите готовый хост из кучи, из него — URL высшего доступного приоритета; «скачивание» имитируйте (печать + задержка); двигайте next_time += 2с.
- Залогируйте порядок и посчитайте: сколько раз воркер «ждал» хост.
Контрольные вопросы
- Почему фронтир разделяют на «очередь важности» и «очередь хостов», а не делают одну приоритетную очередь?
- Какие преобразования URL безопасны на этапе приёма, а какие лучше отложить до каноникализации, и почему?
- Что произойдёт с памятью и качеством обхода, если заменить точную дедупликацию на фильтр Блума? Какой именно сбой это вносит?
- Чем OPIC-распределение отличается от обхода по заранее посчитанной ссылочной важности?
- Как побороть «голодание» низкоприоритетных URL, не ломая приоритизацию?
- Почему DFS опасен для веб-обхода?
- (SEO) Почему ссылка, появляющаяся только после клика по кнопке, может никогда не попасть во фронтир?
Цели обучения
После этой главы студент сможет:
- Сформулировать политику вежливости (per-host rate limit, задержка, конкурентность) и объяснить, зачем она нужна.
- Объяснить и применять оценку частоты изменения страницы для расписания переобхода.
- Вывести интуицию оптимального интервала переобхода для модели обновлений Пуассона.
- Определить ранг обхода (crawl rank) и перечислить его компоненты.
- Объяснить, на что расходуется краулинговый бюджет, и как его экономят.
Скачать страницу один раз — мало: веб меняется, копия устаревает. Поэтому обход делится на открытие (discovery, скачать новое) и обновление (refresh, переобойти известное). И то и другое упирается в две вещи: нельзя перегружать чужие серверы (вежливость) и нельзя превысить собственные ресурсы (бюджет).
Политика вежливости (politeness)
Компоненты политики вежливости:Интуиция. Робот — гость на чужом сервере. Если ломиться сотней запросов в секунду, хозяин примет это за атаку и забанит — а заодно пострадают живые пользователи сайта. Вежливость — это самоограничение скорости в обмен на доступ.
- Минимальная задержка между запросами к хосту (crawl-delay). Часто — фиксированное значение или адаптивное: задержка ≈ k × (время ответа сервера), чтобы автоматически тормозить на медленных серверах.
- Ограничение конкурентности на хост — обычно 1–2 одновременных соединения к одному хосту.
- Уважение объявленных ограничений — директива задержки в правилах доступа, серверные сигналы (429 Too Many Requests, 503, заголовок Retry-After).
- Размазывание по IP, а не только по хосту. Десятки тысяч хостов на одном IP/сервере должны делить общий лимит — иначе «вежливость к хосту» обернётся перегрузкой машины.
Частота переобхода (recrawl) и модель ПуассонаВнимание. Идентификация по User-Agent и обратному DNS — часть вежливости и честности: добросовестный робот представляется и резолвится на свои подсети, чтобы хозяин мог его отличить от подделки (см. 2.3).
Страницы меняются с разной скоростью: лента новостей — ежечасно, статья в архиве — почти никогда. Тратить одинаковый бюджет на обе — расточительство. Нужна оценка частоты изменения λ (changes per unit time) для каждой страницы.
Классическая модель: изменения страницы — пуассоновский процесс с интенсивностью λ. Тогда вероятность того, что к моменту t после последнего обхода страница уже изменилась (наша копия «протухла»), равна 1 − e^(−λ·t). Чем больше λ и чем дольше не заходили — тем вероятнее, что копия устарела.
Оценка λ на практике — по истории: сравниваем контент при последовательных обходах (через контент-хеш/шинглы, см. Модуль 3). Тонкость: если переобходить редко, мы видим «изменилось/нет», но не сколько раз менялось между визитами — оценку λ корректируют с поправкой на это (иначе систематически занижаем частоту у быстро меняющихся страниц).Интуиция. Если страница меняется в среднем раз в день (λ=1/день), то через час после обхода она почти наверняка ещё свежа, а через неделю — почти наверняка протухла. Расписание переобхода должно «ловить» страницу примерно тогда, когда вероятность изменения становится заметной.
Ранг обхода (crawl rank)Заблуждение (важное, контринтуитивное). «Чем чаще страница меняется, тем чаще её надо обходить — пропорционально.» На самом деле при фиксированном бюджете оптимальная политика по свежести не монотонно-пропорциональна: страницы, которые меняются слишком часто относительно бюджета, выгодно обходить реже, чем страницы со средней частотой, потому что угнаться за ними всё равно нельзя, а бюджет они съедают. Оптимум — где-то посередине.
Чтобы решить «кого переобойти/открыть следующим», каждому URL присваивают ранг обхода (crawl rank) — скаляр, агрегирующий несколько сигналов:
Код: Выделить всё
Компонент | Смысл | Откуда
-------------------------+---------------------------------------------------------+---------------------------------------------
Важность | насколько страница ценна для индекса | ссылочная важность (Модуль 7), трафик/спрос
Ожидаемая «протухлость» | 1 − e^(−λ·t) — насколько вероятно, что копия устарела | история изменений
Качество/доверие хоста | стоит ли вообще тратить бюджет | сигналы спама/качества (2.3, Модуль 16)
Стоимость | дорого ли скачать (размер, нужен ли рендеринг) | история загрузок
Свежесть-спрос | есть ли запросы на эту тему сейчас | сигналы спроса (Модуль 17)
Краулинговый бюджет (crawl budget)
Краулинговый бюджет — это ограничение на то, сколько робот готов и может потратить на обход в единицу времени, в пересечении двух пределов:
- Со стороны сайта (crawl capacity / host limit): сколько запросов хост выдержит без деградации (вежливость + наблюдаемая стабильность сервера).
- Со стороны робота (crawl demand): сколько обхода этот сайт «заслуживает» с точки зрения важности и спроса.
SEO-врезка. Краулинговый бюджет — на что он утекает. Бюджет хоста конечен, и его пожирают вещи, не приносящие новых страниц в индекс:
- Дубли по параметрам (?sort=, ?sessionid=, UTM-метки) — робот тратит запросы на сотни URL с одинаковым контентом.
- Бесконечные пространства — календари «следующий месяц→∞», фасетная фильтрация с комбинаторным взрывом, постраничная навигация без конца.
- Цепочки редиректов и мягкие 404 (страница «ничего не найдено» с кодом 200).
- Медленный сервер — высокий time-to-first-byte режет capacity: каждый запрос дороже, значит их меньше.
Как экономят бюджет: канонические URL (Модуль 3), параметры — в robots/через подсказки канонизации, удаление мусорных URL из sitemap, ускорение ответа, чистые 404/410 вместо «мягких». Важно: для малых сайтов бюджет почти никогда не узкое место — оптимизация бюджета актуальна для крупных сайтов с миллионами URL.
Частые заблужденияИнженерная заметка. Бюджет «дышит»: если хост начинает отдавать 5xx/429 или резко замедляется, робот обязан снизить скорость (вежливость как обратная связь). Поэтому реальная скорость обхода — это управляемый контур с обратной связью по здоровью сервера, а не константа.
Заблуждение. «Частые обходы повышают позиции.» Переобход обновляет копию и её свежесть, но сам по себе не повышает релевантность/ранг. Бюджет — про актуальность и полноту индекса, не про ранжирование.
Лаба / практикаЗаблуждение. «У моего сайта мало просмотров от робота — значит, проблема в бюджете.» Чаще причина — низкий спрос (мало важности/интереса) или capacity (медленный сервер), а не «лимит, который можно поднять кнопкой». Бюджет — следствие, а не настройка.
Расписание переобхода под бюджетом. ~45 мин.
Дано: 20 страниц с известными (для проверки) частотами λ от «новостная лента» до «архив». Бюджет: 5 обходов за «тик», горизонт — 30 тиков.
Шаги:
- Оцените «протухлость» каждой страницы как 1 − e^(−λ·t), где t — тиков с последнего обхода.
- На каждом тике выберите 5 страниц с максимальной ожидаемой протухлостью (жадная политика по свежести).
- Считайте суммарную «протухлость» индекса по тикам (метрика freshness).
- Сравните с (а) обходом «всех по кругу» (round-robin) и (б) «чем чаще меняется, тем чаще обходим — пропорционально λ».
- Постройте, при каком λ сверхчастые страницы выгоднее обходить реже.
Контрольные вопросы
- Почему вежливость ограничивают и по хосту, и по IP/серверу одновременно?
- Запишите вероятность того, что копия страницы устарела через время t, в модели Пуассона. Что произойдёт при t→∞?
- Почему «обходить пропорционально частоте изменений» неоптимально при фиксированном бюджете?
- Перечислите минимум четыре компонента ранга обхода и объясните их знак (повышает/понижает приоритет).
- Из каких двух пределов складывается краулинговый бюджет хоста и почему берётся минимум?
- (SEO) Назовите три способа, которыми сайт сам сжигает свой краулинговый бюджет, и как это лечить.
- Почему робот должен снижать скорость в ответ на 429/503, и как это связано с обратной связью?
Цели обучения
После этой главы студент сможет:
- Прочитать и применить протокол исключений для роботов (правила доступа в robots.txt) и метатеги уровня страницы.
- Различать «не обходить» и «не индексировать» и объяснить, почему это разные механизмы.
- Распознавать краулерные ловушки (crawler traps) и описать защиту от них.
- Объяснить угрозы спама в каналах приёма URL и меры противодействия.
- Описать роль бан-листов и репутации хостов в управлении доступом.
Управление доступом отвечает на вопрос «куда роботу ходить нельзя или не нужно» — по чужой воле (правила сайта), по соображениям безопасности (ловушки) и по гигиене (спам, бан-листы).
Протокол исключений для роботов
Стандартный механизм: файл правил в корне хоста (/robots.txt), который добросовестный робот запрашивает и кэширует перед обходом. Базовая модель:
Код: Выделить всё
User-agent: * # к кому относятся правила (маска агента)
Disallow: /admin/ # сюда не ходить
Disallow: /*?sessionid= # маска: URL с этим параметром
Allow: /admin/help # исключение из запрета
Crawl-delay: 5 # подсказка по задержке (не все роботы чтут)
Sitemap: https://host/sitemap.xml # канал обнаружения
- Это договор о доверии, а не техническая защита. Запрет в правилах не закрывает страницу — он лишь просит добросовестного робота не обходить. Закрытие доступа — это авторизация/файрвол, не robots.
- При недоступности файла правил (например, 5xx) корректный робот ведёт себя осторожно (часто — временно не обходит хост), а не «раз нет файла — можно всё».
- Сопоставление по самому длинному/специфичному правилу; синтаксис — построчный, нечувствительный к мелочам, но детали реализации у роботов разнятся.
Уровни управления: обход vs индексация vs следованиеВнимание. Запрет обхода ≠ запрет индексации. Если URL закрыт в правилах обхода, робот его не скачает, а значит не увидит метатег «не индексировать» внутри страницы. Парадокс: закрытая в robots страница всё равно может попасть в выдачу (по внешним ссылкам, без сниппета), потому что директиву «не индексировать» робот не смог прочитать. Чтобы убрать страницу из индекса — её надо разрешить к обходу и поставить директиву noindex, либо закрыть авторизацией.
Код: Выделить всё
Механизм | Где | Что делает | Робот должен скачать страницу?
---------------------+-----------------------------+--------------------------------------------------+--------------------------------
Disallow в правилах | /robots.txt | не обходить URL | нет (он и не качает)
noindex | мета-тег/заголовок ответа | не включать в индекс | да (иначе не прочтёт)
nofollow | мета/атрибут ссылки | не передавать «вес» по ссылке / не идти по ней | да
Канонизация | link rel=canonical | «считай за другой URL» | да (Модуль 3)
Авторизация | сервер | реальный запрет доступа | нет (получит 401/403)
Краулерные ловушки (crawler traps)SEO-врезка. Самая частая ошибка управления доступом: закрыть в robots страницу, которую хотели убрать из индекса. Результат обратный — она остаётся в выдаче «вслепую». Правило: скрыть от обхода (экономия бюджета на мусоре) и убрать из индекса (noindex) — разные задачи с разными инструментами, их нельзя путать.
Ловушка — это область сайта, порождающая практически бесконечный поток новых URL с малой или нулевой ценностью. Они бывают непреднамеренные и злонамеренные:
- Календарь без конца: ...?date=2099-12 → «следующий месяц» → ∞.
- Фасетная фильтрация: комбинации фильтров ?color=&size=&brand=... дают комбинаторный взрыв URL с почти одинаковым контентом.
- Зацикленные относительные ссылки: /a/b/a/b/a/b/... из-за кривой генерации путей.
- Идентификаторы сессий в URL: каждый визит — «новый» URL на тот же контент.
- Сети-ловушки (spider traps) специально для роботов: динамически генерируемые «пауки сетей» страниц, иногда — для траты ресурсов недобросовестных ботов.
- Лимит глубины и лимит числа URL на хост/каталог.
- Обнаружение почти-дублей на лету (контент одинаков → понизить приоритет ветки, см. Модуль 3).
- Эвристики на форму URL: рост длины, повтор сегментов, монотонно растущий числовой параметр.
- Затухание приоритета для ветки, которая рождает много URL и мало нового контента (бюджет ветки исчерпывается).
- Уважение к robots/параметрам, которыми сайт сам помечает «не ходи сюда».
Спам в каналах приёма URLПример. Робот видит /cal/2026-06, на ней ссылку /cal/2026-07, и так далее. Без лимита глубины и без эвристики «контент почти не меняется, параметр монотонно растёт» он будет генерировать по новому URL на каждый месяц до бесконечности, проедая бюджет хоста. С лимитом глубины 4 и детектором «монотонный параметр + почти-дубль» ветка обрезается после нескольких шагов.
Каналы прямой приёмки (push/ping, отправка sitemap, формы «добавить URL») — открытая дверь, через которую можно завалить фронтир мусором или мишенями:
- Флуд URL: массовая отправка бессмысленных/генерированных адресов, чтобы раздуть фронтир и отвлечь бюджет.
- Накрутка обнаружения малоценных/спам-страниц, чтобы их быстрее обошли.
- Отравление каналов: sitemap, набитый чужими/несуществующими URL.
- Аутентификация владения хостом для приоритетных каналов приёмки (право подавать sitemap имеет верифицированный владелец).
- Квоты и троттлинг на источник приёмки.
- Низкое стартовое доверие прямой приёмки: принятый URL получает низкий ранг обхода, пока не подтвердит ценность.
- Репутация хоста/источника как множитель доверия.
Бан-лист (deny/ban list) — явный список хостов/паттернов, которые робот не обходит или обходит с минимальным приоритетом: подтверждённые источники вредоносного контента, чистые спам-фермы, «зеркала-ловушки». Это крайняя мера; чаще работает мягкая репутация: множитель в ранге обхода, который для плохих хостов давит приоритет почти до нуля, не запрещая обход формально. Репутация связана с антиспамом выдачи (Модуль 16): сигналы качества переиспользуются и на этапе обхода — нет смысла тратить бюджет на то, что всё равно отфильтруется при ранжировании.
Частые заблужденияИнженерная заметка. Управление доступом — это слои фильтров на входе во фронтир: robots → бан-лист/репутация → эвристики ловушек → квоты приёмки. Каждый слой должен быть дёшев (срабатывать до загрузки) и fail-safe: при сомнении — понизить приоритет, а не бездумно качать.
Заблуждение. «Закрыл страницу в robots — она исчезнет из поиска.» Наоборот: робот её не скачает и не прочитает noindex, поэтому она может остаться в выдаче «вслепую». Для удаления нужен noindex (с разрешённым обходом) или авторизация.
Лаба / практикаЗаблуждение. «robots.txt защищает приватные данные.» Нет. Это вежливая просьба добросовестным роботам, а не контроль доступа. Недобросовестный бот его проигнорирует; более того, перечисление секретных путей в Disallow их же и раскрывает. Приватное закрывают авторизацией.
Парсер правил доступа + детектор ловушек. ~50 мин.
Часть А (правила): реализуйте is_allowed(url, rules) для подмножества протокола: User-agent, Disallow, Allow, маски с * и якорем $, выбор правила по наибольшей длине совпадения. Прогоните на 10 тест-кейсах (включая Allow-исключение внутри Disallow).
Часть Б (ловушки): на потоке из ~100 URL одного хоста реализуйте эвристики: (1) лимит глубины по числу сегментов; (2) детектор «монотонно растущего числового/датного параметра»; (3) детектор повторяющихся сегментов пути. Помечайте подозрительные URL и понижайте им приоритет.
Критерий «сделано»: для правил совпало с эталоном на всех кейсах, включая длинно-специфичный Allow; календарная ловушка обрезана после N шагов; объяснено, почему фильтры стоят до загрузки и почему они fail-safe.
Контрольные вопросы
- Чем «не обходить» (Disallow) принципиально отличается от «не индексировать» (noindex)? Какой парадокс возникает при их путанице?
- Почему правила доступа — это договор о доверии, а не защита? Как тогда закрыть приватные данные?
- Приведите три вида краулерных ловушек и по одной эвристике защиты для каждой.
- Как недобросовестный отправитель может навредить через канал прямой приёмки URL и какие три меры это гасят?
- Чем «мягкая репутация хоста» лучше жёсткого бан-листа в большинстве случаев?
- Как должен повести себя корректный робот, если /robots.txt отдаёт 503?
- (SEO) Клиент закрыл раздел в robots, но страницы всё ещё в выдаче. Объясните причину и дайте верное решение.
Цели обучения
После этой главы студент сможет:
- Описать конвейер загрузки: DNS → соединение → ответ → обработка, и где он узкие места.
- Объяснить разницу между исходным HTML и отрендеренным DOM и почему рендеринг на порядок дороже.
- Спроектировать двухфазную модель обхода (скачать → при необходимости отрендерить) и бюджет рендеринга.
- Перечислить шаги потоковой постобработки (определение типа, кодировки, языка, извлечение ссылок и текста).
- Оценить риски рендеринга (стоимость, недетерминизм, безопасность) и способы их снижения.
Конвейер скачивания
Загрузка одного документа — это цепочка, в которой каждое звено может стать узким местом:
Код: Выделить всё
URL → [DNS-резолв] → [TCP/TLS-соединение] → [HTTP-запрос]
→ [получение заголовков] → [потоковое чтение тела] → [постобработка]
- Свой кэш DNS — резолв десятков миллиардов раз нельзя гонять на внешние резолверы; кэш с TTL обязателен.
- Пул переиспользуемых соединений (keep-alive) — рукопожатие TLS дорого, его амортизируют.
- Жёсткие таймауты и лимиты размера — иначе один «висящий» сервер или гигантский файл заблокирует воркера.
- Условные запросы при переобходе: If-Modified-Since/If-None-Match → ответ 304 Not Modified экономит и трафик, и бюджет (страница не изменилась — тело не качаем).
- Уважение кодов: 2xx — обрабатываем; 3xx — переход по редиректу (с лимитом длины цепочки и защитой от циклов); 4xx — обычно отбрасываем (410 сильнее 404); 5xx/429 — повтор позже с backoff и снижением скорости.
Исходный HTML vs отрендеренный DOMИнженерная заметка. Робот сетевой, а не процессорный — пока ждёт ответа, процессор простаивает. Поэтому загрузчики делают массово-асинхронными (тысячи одновременных соединений на воркер), а не «поток на запрос». Дисциплина вежливости при этом сохраняется через хост-очереди (2.1).
Раньше «скачать страницу» = получить финальный HTML. Сегодня значительная часть контента появляется только после исполнения JavaScript в браузере: данные подгружаются запросами, DOM достраивается на клиенте. Возникает разрыв:
- Исходный HTML (raw/source HTML) — то, что отдал сервер. Дёшево скачать и распарсить. Может быть почти пустой каркас (<div id="app"></div>).
- Отрендеренный DOM (rendered DOM) — состояние страницы после загрузки и исполнения скриптов в реальном движке браузера. Здесь виден весь контент и ссылки, появившиеся динамически.
Двухфазная модель обходаИнтуиция. Скачать исходный HTML — как сфотографировать рецепт. Отрендерить — как реально приготовить блюдо: нужен «полноценный браузер», время, память и иногда сетевые до-загрузки. Поэтому рендеринг в 10–100× дороже простого скачивания и применяется выборочно.
Из-за стоимости рендеринг не делают для всех страниц. Типичная двухфазная схема:
Код: Выделить всё
Фаза 1 (дёшево, всем): скачать исходный HTML → распарсить → извлечь
то, что видно без JS (ссылки, текст, метаданные)
│
▼ нужен ли рендеринг? (эвристика: каркас пустой / есть тяжёлый JS /
│ важная страница / прошлый раз дал больше контента)
▼
Фаза 2 (дорого, выборочно): очередь рендеринга → headless-браузер исполняет JS
→ отрендеренный DOM → повторное извлечение
SEO-врезка. Что видит робот без рендеринга. В Фазе 1 робот видит только исходный HTML. Если важный контент и ссылки появляются лишь после исполнения JS, то до Фазы 2 (которая может задержаться или не наступить из-за бюджета рендеринга) они для робота не существуют. Практические следствия:
- критичный контент и навигация должны присутствовать в исходном HTML (server-side rendering / гидратация / пререндер);
- ссылки — настоящими <a href>, не «по клику»;
- данные через fetch после загрузки могут быть не увидены или увидены с задержкой;
- рендеринг — это очередь и бюджет: «работает в моём браузере» ≠ «робот это увидел».
Потоковая постобработка (streaming processing)Внимание. Недетерминизм рендеринга. Отрендеренный DOM зависит от таймаутов, доступности сторонних ресурсов, согласия на cookies, A/B-экспериментов сайта. Два рендера одной страницы могут отличаться. Робот ограничивает время рендера, блокирует ненужные ресурсы (аналитику, рекламу) и фиксирует «разумную точку» (например, событие готовности сети/DOM), а не «ждёт бесконечно».
Скачанное тело не ждут целиком в памяти — его обрабатывают потоком, по мере поступления байт, и рано отбрасывают ненужное:
- Определение типа контента (MIME) — по заголовку и сигнатуре («магическим байтам»); не-HTML (изображения, архивы) уходят по своим веткам или отбрасываются.
- Определение кодировки (charset) — из заголовка/<meta>/эвристикой по байтам; всё приводят к единому Unicode-представлению, иначе текст «поедет».
- Ранний отказ — превышен лимит размера, тело не HTML, явный мусор → разорвать соединение, не дочитывая.
- Парсинг в потоке — токенизатор HTML работает по мере чтения; извлечение ссылок (для возврата во фронтир) можно начать ещё до конца документа.
- Извлечение основного текста — отделение контента от «обвязки» (меню, футер, реклама) — boilerplate removal; нормализация пробелов.
- Определение языка — для маршрутизации и языковых сигналов (Модуль 18).
- Контент-хеш/шинглы — отпечаток для дедупликации и оценки «изменилось ли» (Модуль 3).
- Передача дальше — извлечённые ссылки → приём URL (2.1); текст и метаданные → каноникализация и индексирование (Модули 3, 4).
Интуиция. Постобработка — конвейер, а не «скачали → потом подумали». Чем раньше отброшен мусор и извлечены ссылки, тем меньше памяти и тем быстрее новые URL попадают во фронтир. Робот работает на потоке, как сортировочная лента, а не как склад.
Внимание. Безопасность загрузчика. Робот качает враждебный контент: «архивные бомбы» (распаковка в терабайты), гигантские/зацикленные ответы, попытки заставить ходить во внутреннюю сеть (SSRF через редиректы на приватные адреса). Защита: лимиты размера и времени, запрет редиректов на приватные диапазоны IP, изоляция (sandbox) headless-браузеров — особенно при рендеринге, где исполняется чужой JS.
Частые заблужденияИнженерная заметка. Headless-браузеры текут по памяти и нестабильны под нагрузкой. Их держат в пуле с принудительным перезапуском (после N страниц), жёстким таймаутом на рендер и блокировкой лишних ресурсов. Бюджет рендеринга и стабильность пула — главные эксплуатационные боли Фазы 2.
Заблуждение. «Если страница открывается в браузере и контент виден — значит, робот его тоже видит.» Браузер всегда исполняет JS; робот — только в дорогой Фазе 2 и не для всех страниц. То, что видно после JS, может быть невидимо роботу или увидено с большой задержкой.
Лаба / практикаЗаблуждение. «Сначала скачаем всё тело, потом разберёмся.» Промышленный робот обрабатывает поток и рано отбрасывает мусор: иначе один гигантский/враждебный ответ съест память и заблокирует воркера.
Двухфазная обработка и решение о рендеринге. ~55 мин.
Дано: 15 «страниц» — пары (исходный HTML, «отрендеренный» HTML после JS). Часть имеют почти пустой каркас, часть полны контента уже в исходнике.
Шаги:
- Реализуйте конвейер Фазы 1: определить «тип» и кодировку (упрощённо), извлечь <a href>, извлечь видимый текст, посчитать «долю контента» (текст/разметка).
- Эвристика рендеринга: пометьте страницу «нужен рендер», если в исходнике мало текста/ссылок, но это важная страница. Сформируйте отдельную очередь рендеринга с бюджетом (например, можно отрендерить только 5 из 15).
- Для «отрендеренных» (имитация Фазы 2) повторно извлеките ссылки/текст и сравните прирост.
- Посчитайте: сколько ссылок было бы потеряно без рендеринга и сколько бюджета рендеринга ушло.
- Добавьте защиту: лимит размера тела и отказ обрабатывать не-HTML.
Контрольные вопросы
- Перечислите звенья конвейера скачивания и назовите по одному узкому месту в каждом.
- Зачем роботу собственный кэш DNS и пул keep-alive соединений?
- Как условные запросы (If-Modified-Since/304) экономят краулинговый бюджет?
- В чём разница между исходным HTML и отрендеренным DOM и почему рендеринг на порядок дороже?
- Опишите двухфазную модель обхода. Что такое «бюджет рендеринга» и почему он дефицитнее обычного?
- Перечислите минимум пять шагов потоковой постобработки и объясните, зачем «ранний отказ».
- Какие угрозы безопасности несёт загрузка и рендеринг враждебного контента и как их снижают?
- (SEO) Контент подгружается через fetch после загрузки страницы. Объясните, почему он может не попасть в индекс, и что с этим делать.
- Обход — это приоритизация под бюджетом. Главный вопрос не «как скачать URL», а «что скачать следующим и стоит ли вообще» при конечных ресурсах и почти бесконечном вебе.
- Фронтир разделяет «что» и «когда». Верхний уровень очередей — по важности (ранг обхода), нижний — по хостам ради вежливости; дедупликация и нормализация URL — обязательные инварианты на входе.
- Вежливость — это контур с обратной связью. Робот ограничивает скорость по хосту и IP и снижает её в ответ на ошибки/замедление сервера; иначе он выглядит как атака и теряет доступ.
- Переобход — про свежесть, не про ранг. Частоту обновлений моделируют (Пуассон, 1 − e^(−λt)); при фиксированном бюджете слишком быстрые страницы выгодно обходить реже, а не чаще.
- Краулинговый бюджет = min(capacity, demand). Его сжигают дубли по параметрам, бесконечные пространства, редиректы и медленный сервер; для малых сайтов он редко узкое место.
- Управление доступом многослойно и fail-safe. robots (договор о доверии, не защита), репутация/бан-листы, эвристики ловушек, квоты приёмки — всё до загрузки. «Не обходить» ≠ «не индексировать».
- Рендеринг — отдельный дорогой бюджет. Двухфазная модель: дёшево скачать всем, дорого отрендерить выборочно. Контент только-после-JS может быть невидим роботу или увиден с задержкой.
- Постобработка потоковая. Тип, кодировка, язык, извлечение ссылок и текста, контент-хеш — по мере чтения, с ранним отбрасыванием мусора и защитой от враждебного контента.
- Фронтир (frontier) — структура данных, хранящая URL, намеченные к обходу, с метаданными приоритизации.
- Приём URL (URL ingestion) — этап нормализации, фильтрации и дедупликации URL перед постановкой во фронтир.
- Каналы обнаружения — источники новых URL: ссылки, sitemap, прямая приёмка, переобход.
- Двухуровневая очередь — схема фронтира: очереди важности (что) поверх очередей хостов (когда).
- Фильтр Блума (Bloom filter) — компактная вероятностная структура для дедупликации URL («точно нет»/«возможно да»).
- OPIC — онлайновое вычисление важности страниц через «раздачу наличности» по ссылкам, задающее порядок обхода.
- Политика вежливости (politeness) — самоограничение частоты и конкурентности запросов к хосту/IP.
- Crawl-delay — минимальная задержка между запросами к одному хосту.
- Переобход (recrawl) — повторное скачивание известного URL для обновления копии.
- Ранг обхода (crawl rank) — скаляр приоритета обхода, агрегирующий важность, протухлость, доверие, стоимость.
- Краулинговый бюджет (crawl budget) — лимит обхода хоста как минимум из capacity (сервер) и demand (спрос).
- Crawl capacity / crawl demand — пределы бюджета со стороны сервера и со стороны интереса поисковика.
- Протокол исключений для роботов — правила доступа (robots.txt) — договор о вежливом обходе, не защита.
- noindex / nofollow — директивы уровня страницы/ссылки: не индексировать / не идти по ссылке (читаются только после скачивания).
- Краулерная ловушка (crawler trap) — область сайта, порождающая бесконечный поток малоценных URL.
- Бан-лист / репутация хоста — явный запрет или мягкий множитель доверия в ранге обхода.
- Исходный HTML / отрендеренный DOM — состояние страницы до и после исполнения JavaScript.
- Двухфазный обход — дешёвое скачивание всем + дорогой выборочный рендеринг в отдельном пуле.
- Бюджет рендеринга — отдельный дефицитный лимит на исполнение JS в headless-браузерах.
- Потоковая постобработка — обработка тела ответа по мере чтения: тип, кодировка, язык, ссылки, текст, хеш.
- Контент-хеш / шинглы — отпечаток содержимого для дедупликации и детекции изменений.
- Опирается на: Модуль 0 (обзор конвейера, базовый цикл обхода), Модуль 1 (основы IR, структуры данных, понятие важности документа).
- Ведёт в: Модуль 3 (каноникализация и дубли — куда уходят извлечённый текст и контент-хеши; решения о тождестве URL, отложенные на этапе приёма), Модуль 4 (индексирование — потребитель очищенного контента).
- Перекликается с: Модуль 7 (ссылочная важность как источник ранга обхода), Модуль 16 (сигналы качества/антиспама переиспользуются как репутация хоста при обходе), Модуль 17 (свежесть и реалтайм — спрос как компонент переобхода), Модуль 18 (определение языка/гео в постобработке).
- Классические работы по архитектуре масштабируемых веб-роботов (распределённый фронтир, дисциплина вежливости, классические схемы front/back-очередей).
- Обзоры по политикам переобхода и оптимизации свежести индекса под бюджетом (пуассоновские модели изменений, политики обновления).
- Литература по онлайновому вычислению важности страниц (OPIC-подобные подходы) и приоритизации обхода.
- Материалы по протоколу исключений для роботов и стандартам объявления URL (sitemap-подобные форматы) — на уровне принципов, без привязки к конкретным реализациям.
- Инженерные обзоры по headless-рендерингу в роботах: стоимость, недетерминизм, изоляция, защита от враждебного контента (архивные бомбы, SSRF).
- Работы по обнаружению почти-дублей (шинглы, отпечатки) — как защита от ловушек и основа дедупликации (готовит почву для Модуля 3).