Перейти к содержимому

Изменения на сайтах

Следите за содержимым веб-страницы или всего сайта и получайте уведомление, когда оно меняется: страница с ценами или условиями, сайт документации, уведомление поставщика о техобслуживании, страница публичных объявлений или ваш собственный сайт после развёртывания. Каждое изменение сохраняется с текстом до и после, построчным diff и, если доступен браузер, снимком экрана каждой версии.

Сравнивается видимый текст каждой страницы, а не её HTML: скрипты, стили, комментарии, блоки noscript, svg и template отбрасываются, пробельные символы схлопываются, а каждый блок (абзац, заголовок, элемент списка, строка таблицы) становится одной строкой. Новая сборка той же страницы, изменённый порядок атрибутов или новое имя ресурса с защитой от кэша ничего не меняют; переформулированное предложение — меняет.

Навигация, шапка, подвал и боковые панели сайта не учитываются: они одинаковы на каждой странице, и иначе новый пункт меню пометил бы все страницы как изменённые за одну проверку. Они определяются по ролям, которые даёт HTML: любой nav, header или footer, не находящийся внутри article, aside, main, nav или section (шапка статьи сохраняется), aside вне article и main, и любой элемент с ролью navigation, banner, contentinfo или search. Их ссылки по-прежнему обходятся, чтобы находить страницы сайта. Опция Compare menus, header and footer отключает это исключение.

Watched area ограничивает сравнение некоторыми элементами, например main или #content; страница, на которой ни один из них не найден, читается целиком, а не как пустая. Excluded areas исключает дополнительные элементы: баннер cookie, блок «последние записи», рекламное место. Оба поля принимают простые селекторы через запятую: тег (main), идентификатор (#content), классы (.cookie-banner), атрибуты ([role=alert], [data-ad]) или несколько из них вместе (div.notice[role=alert]). Потомки (main p) и другие комбинаторы не поддерживаются.

Page (по умолчанию) читает только адрес монитора и ничего больше. Это может быть и обычный текстовый или JSON-документ, сравниваемый построчно.

Site начинает с адреса и обходит все страницы в той же папке (https://example.com/docs/intro.html охватывает всё под /docs/; Path prefix выбирает другую папку). Страницы находятся:

  1. в карте сайта: в тех, о которых сообщает robots.txt (строки Sitemap:), или в /sitemap.xml, включая индексы карт сайта (один уровень);
  2. если этого нет или если карта сайта ничего не содержит под этой папкой — по ссылкам каждой страницы, в ширину.

Обходятся только страницы того же origin (схема, хост и порт). Если начальная страница перенаправляет на другой хост того же сайта (example.com на www.example.com, http на https или поддомен вроде docs.example.com), считается, что сайт находится там, и ссылки на первый хост читаются на втором. Если она перенаправляет на совсем другой сайт (страница входа вроде login.microsoftonline.com, сторонний домен), этот сайт не обходится: читается только начальная страница, и ни одна страница не сообщается как удалённая. Ссылки на изображения, таблицы стилей, скрипты, PDF, архивы и другие файлы пропускаются по расширению, а любой ответ, не являющийся HTML, игнорируется. Фрагменты (#section), параметры отслеживания (utm_…, fbclid, gclid и подобные) и пустые запросы удаляются, так что одна страница — это один адрес; опция Ignore query strings отбрасывает всю часть ?…. Для страниц, найденных таким способом, соблюдается robots.txt: группа, названная DumbMonit, а при её отсутствии группа *, с Allow, Disallow, * и $.

Обход вежливый: не более двух запросов одновременно, полсекунды между двумя пакетами, User-Agent DumbMonit/<version>, тайм-аут 15 секунд на запрос и не более 5 МБ чтения на страницу. Он останавливается на Max pages (по умолчанию 25, максимум 200) или через десять минут. Если его остановил Max pages, страница монитора сообщает, сколько страниц найдено, чтобы ненаблюдаемая часть сайта не стала сюрпризом. User agent заменяет DumbMonit/<version> для сайта, который отсекает роботов.

Монитор опрашивается как любой другой (по умолчанию каждую минуту), но страницы читаются только раз в Check every минут (по умолчанию 60, от 5 до 10080). В промежутках опрос лишь сообщает состояние последней проверки: сайт не нагружается каждую минуту. Проверка выполняется в фоне; две проверки одного монитора никогда не пересекаются, а Check now на странице монитора запускает проверку немедленно.

Первая проверка только записывает эталон: каждая страница читается и сохраняется, ничего не сообщается. Начиная с этого момента для каждой страницы:

СитуацияЧто сохраняется
Тот же текст, что и в прошлый раз (после Ignore lines)Ничего нового; страница помечается как проверенная.
Другой текстНовый снимок и событие changed с числом добавленных и удалённых строк.
Страница, которой раньше не было, или которая появилась снова после исчезновенияСнимок и событие new page.
Страница отвечает 404 или 410Событие removed page, последний снимок как «до».
Область «сайт»: полный обход больше не достигает известной страницыТоже событие removed page («No longer linked»). Обход, остановленный по Max pages или по лимиту времени, никогда не делает вывода, что страница исчезла.
Любая другая ошибка на странице (тайм-аут, 403, 500 на вложенной странице)Ошибка показывается на странице; события нет.

Смена адреса, области, префикса пути, Max pages, областей или Ignore lines делает следующую проверку новым эталоном, вместо того чтобы сообщать, что изменилась каждая страница (а при увеличении Max pages — что новой стала каждая добавленная страница). Обновление DumbMonit, которое иначе читает страницы, делает то же самое один раз.

Если одна проверка находит одно и то же изменение на нескольких страницах (те же удалённые и добавленные строки, например баннер), страница монитора показывает его один раз, с перечнем страниц, на которых оно произошло.

Строки, меняющиеся при каждом посещении, — часы, счётчик посетителей, «обновлено 5 минут назад», случайная цитата — сообщались бы при каждой проверке. Ignore lines содержит регулярные выражения (синтаксис Rust regex), по одному в строке или через |; любая текстовая строка, которой соответствует одно из них, исключается перед сравнением. Например:

Updated \d+ minutes ago|Visitors: \d+|© \d{4}

Когда саму начальную страницу не удаётся прочитать (нет ответа, соединение отклонено, тайм-аут, HTTP 5xx), монитор недоступен: опрос завершается ошибкой, и правило «Monitor unreachable» срабатывает как для любого монитора. Начальная страница затем перепроверяется при каждом опросе, поэтому её возвращение заметно в течение минуты. Начальная страница, отказывающая в доступе (401, 403), сообщается как проблема конфигурации, а не как сбой. Ошибки на других страницах сайта показываются только на этих страницах.

Адреса, доступные только самому хосту DumbMonit (loopback, link-local, служба метаданных облака), отклоняются, если не включена опция Allow loopback and link-local targets; адреса частной LAN разрешены всегда.

Встроенное правило Website changed (webchange_detected, Info) срабатывает после проверки, обнаружившей хотя бы одно изменение (изменённая, новая или удалённая страница), и уведомление называет страницы: «/pricing, /contact и ещё 2». Пока оповещение активно, каждая следующая проверка, находящая изменения, уведомляет снова, со своими страницами, даже если страницы те же; оповещение снимается при первой проверке, не нашедшей ничего нового. Оно остаётся одним оповещением на монитор всё это время, поэтому подтверждение или откладывание оповещения охватывает и последующие проверки. Оно читает dumbmonit_webchange_last_check_changes; привяжите его к каналу, как любое другое правило, или повысьте его серьёзность в Alerts → Rules. См. Встроенные правила.

МетрикаЧто
dumbmonit_webchange_pagesОбойдённые страницы (удалённые не учитываются).
dumbmonit_webchange_pages_failedОбойдённые страницы, последнее чтение которых завершилось ошибкой.
dumbmonit_webchange_last_check_changesИзменения, найденные последней проверкой.

Метрики появляются после завершения первой проверки.

В образе DumbMonit нет браузера: снимки экрана делает необязательный headless Chromium, управляемый по Chrome DevTools Protocol. Добавьте его как службу browser рядом с DumbMonit в docker-compose.yml и укажите на него серверу:

services:
dumbmonit:
environment:
DUMBMONIT_BROWSER_URL: http://browser:9222
browser:
image: chromedp/headless-shell:stable
shm_size: 256m
restart: unless-stopped

Затем выполните docker compose up -d. Порт браузера никуда не публикуется: с ним общается только сервер DumbMonit, по сети Compose.

DUMBMONIT_BROWSER_URL указывает DumbMonit на браузер (подойдёт любой Chromium, запущенный с --remote-debugging-port, например chromedp/headless-shell; сервер читает /json/version и обращается к адресу, в который разрешается имя хоста).

Снимок экрана делается только тогда, когда страница получает новый снимок (эталон и каждое изменение), и никогда при неизменённой проверке: окно 1366 × 900, вся страница до 5000 пикселей, в формате JPEG. Опция Screenshots отключает их для одного монитора. Без браузера или когда он не отвечает, текстовое сравнение работает так же, а у снимков просто нет изображения; страница монитора сообщает об этом.

Браузер загружает страницу так, как это делал бы посетитель, вместе со скриптами: то, что он показывает, может отличаться от текста, который сравнил DumbMonit, — то есть от HTML, отправленного сервером.

Текст каждого снимка хранится в базе данных (не более 1 МБ на страницу); снимки экрана — это файлы в /data/webchange/<device id>/. На монитор хранятся последние 500 изменений; снимок хранится, пока он является последним для страницы или на него ссылается сохранённое изменение, а всё остальное, включая файлы, удаляется после каждой проверки. Удаление монитора удаляет всё это.

Ниже приведены шаги, которые показывает уведомление рядом с формой.

  1. В адресе вставьте страницу для наблюдения, с http:// или https://. Чтобы следить за всем сайтом или одним из его разделов, вставьте его начальную страницу и установите «Scope» в «site»: будут обойдены все страницы в той же папке, до «Max pages».
  2. Строки, меняющиеся при каждом посещении (часы, счётчик посетителей, «обновлено 5 минут назад»), сообщались бы каждый раз: перечислите их в «Ignore lines» как регулярные выражения.
  3. Первая проверка только записывает эталон, ничего не сообщается. Начиная с этого момента каждая проверка сравнивает видимый текст страница за страницей и сохраняет копию «до/после» каждого изменения, показываемую на странице монитора; об изменении сообщает оповещение «Website changed».
  4. Чтобы получать снимок экрана каждой версии, добавьте в файл Compose headless-браузер; точные строки приведены в документации (Дополнительные параметры, «Снимки экрана при изменениях сайтов»). См. Снимки экрана при изменениях сайтов.

Учётные данные: нет. Проверки всегда выполняются на сервере DumbMonit: наблюдение за сайтом не может идти через relay-агент.

ПараметрПо умолчаниюЗначение
Scope (scope)pagepage: только адрес. site: все страницы в той же папке.
Max pages (max_pages)25Область «сайт»: максимум страниц, читаемых за проверку, от 1 до 200.
Path prefix (path_prefix)папка адресаОбласть «сайт»: только страницы, путь которых начинается с этого (/docs/).
Ignore lines (ignore)—Регулярные выражения; соответствующие им текстовые строки не сравниваются.
Watched area (content_selector)—Простые селекторы; сравнивается только текст внутри них.
Excluded areas (exclude_selector)—Простые селекторы; их текст не сравнивается.
Compare menus, header and footer (keep_page_chrome)falseСравнивать также навигацию, шапку, подвал и боковые панели сайта.
Ignore query strings (ignore_query)falseОбласть «сайт»: адреса, отличающиеся только частью ?…, считаются одной страницей.
User agent (user_agent)—Отправляется вместо DumbMonit/<version>.
Screenshots (screenshots)trueХранить снимок экрана каждой новой версии, если настроен браузер.
Check every (check_interval_minutes)60Минут между двумя проверками, от 5 до 10080.
Accept an unverifiable certificate (insecure_tls)falseДля вашего собственного сайта с самоподписанным сертификатом.
Allow loopback and link-local targets (allow_private_targets)falseОбращаться к сайту, который обслуживает сам хост DumbMonit.