Задача звучала просто. Есть большой каталог франшиз - витрина, где сотни карточек с ценами входа. Надо понять, насколько быстро эта витрина обновляется: сколько предложений, которые человек видел два года назад, дожили до сегодня.
Вопрос не праздный. Каталог франшиз читают как справочник, и возраст предложения в нём воспринимается как возраст бизнеса за ним. Проверить это можно только одним способом - сравнить два состояния каталога в разные годы.
Ниже история про то, как я это сделал, и почему повторить уже не смогу: источник закрылся не только от меня, но и от веб-архива.
Живой сайт меня не пускает
Первая мысль была очевидной: обойти каталог сейчас, а прошлое достать из архива. Не вышло сразу.
На любом адресе, вплоть до корня сайта, мой сервер получает 421. Не 403, не капчу, а именно 421 - Misdirected Request. Этот код обычно означает, что запрос пришёл на сервер, который не обслуживает этот домен; на практике его часто отдаёт защитный слой перед сайтом, когда решает, что соединение ему не нравится.
Проверил через обычный браузер Playwright с честным user-agent - тот же 421. Попробовал с другой машины - страница открывается нормально. То есть дело в адресе сервера, а не в способе запроса.
Здесь важно назвать вещи своими именами, а не заявить «сайт лежит». Доступность с сервера и доступность для читателя - разные вещи. У меня сервер за границей, и половина рунета встречает его совсем не так, как встречает домашний интернет. Я на этом уже обжигался: пара площадок, которые «не работали», прекрасно открывались у человека из дома.
Раз живой сайт закрыт, остаётся архив.
Два снимка вместо обхода
Веб-архив оказался не запасным вариантом, а лучшим.
Если брать данные из архива с обеих сторон, оба среза сняты одним способом. Это важнее, чем свежесть: когда один срез собран обходом живого сайта, а другой из архива, любое расхождение можно списать на разницу методов. А так метод один, различаются только даты.
Взял два состояния: январь 2024 года и август 2026-го. Двенадцать категорий каталога, одни и те же в обоих срезах - если категории поедут, поедет и выборка.
Дальше разбор страниц и сопоставление. Считается ровно одно: совпадают ли адреса карточек. Не названия - названия переписывают, - а именно адреса.
было = {з["путь"]: з for з in старое["записи"]} стало = set(новое["пути"]) осталось = sorted(п for п in было if п in стало) ушло = sorted(п for п in было if п not in стало) пришло = sorted(п for п in стало if п not in было)
Три множества, ничего сложного. Сложное начинается там, где надо решить, что эти множества означают.
Что число значит, а что нет
Получилось так:
в январе 2024 года на витрине 285 карточек;
в августе 2026-го - 201;
из прежних дожили 62, это 22 процента;
исчезли 223;
появились 139 новых, то есть 69 процентов нынешней витрины.

И вот тут главный соблазн, которому нельзя поддаваться. Число 22 процента просится в заголовок «три четверти франшиз закрываются за два года». Так писать нельзя, потому что измерено не это.
Исчезнувшая карточка означает ровно одно: этого адреса во втором снимке нет. За таким исчезновением стоит что угодно: франчайзер закрылся, перестал продавать франшизу, ушёл в другой каталог, поссорился с площадкой или просто перестал платить за размещение. Данные не позволяют выбрать между этими версиями, и значит выбирать нельзя.
Это общее правило работы с чужими витринами: вы меряете витрину, а не рынок за ней. Я держу эту формулировку прямо в скрипте, в строке документации, чтобы она попадала в глаза раньше, чем результат.
Цены: где выборка честно схлопывается
Отдельный срез - что стало с ценой входа у тех, кто дожил.
Переживших 62. Казалось бы, вот и выборка. Но цена нашлась в обоих снимках только у 24 из них: где-то строка стартовых инвестиций в старом снимке не сохранилась, где-то формат записи изменился так, что сравнивать нечего.
Из этих 24 подорожали 8, подешевели 3, а 13 остались при своей цифре. Медианный рост - ноль процентов.
Соблазн здесь обратный: хочется вытянуть выборку до 62, дописав пропуски «примерно». Нельзя. Двадцать четыре - это и есть честный размер, и его надо назвать вслух рядом с результатом, иначе читатель решит, что речь про все шестьдесят два.
Третий срез: как источник закрылся окончательно
К сентябрю захотелось третьей точки. Тут выяснилось, что архив обходил каталог последний раз 15 августа, и сам по себе новых снимков не сделает.
У веб-архива есть механизм заказа снимка - Save Page Now. Нужны ключи, дальше это обычный запрос: просишь сохранить адрес, получаешь номер задания, потом проверяешь статус. Написал скрипт на все двенадцать категорий.
Первая же ловушка - предел одновременных заданий:
You have already reached the limit of active Save Page Now
Это не ошибка запроса, а очередь. Правильная реакция - подождать и повторить, а не считать категорию несобранной. Первый прогон у меня взял ровно половину категорий именно потому, что на эту строку скрипт реагировал как на отказ.
Починил, запустил заново - и получил на каждом задании одно и то же:
The target server blocks access to https://... (HTTP status=403)
Архив принял задания, честно сходил за страницами и получил отказ. То есть каталог блокирует не только мой сервер, но и обходчик веб-архива.
Третьего среза не будет. Не потому, что я неправильно попросил, а потому, что источник закрыт для сохранения в принципе - пока сайт не изменит правила.
Что я из этого забрал
Источник может исчезнуть, и данные надо считать скоропортящимися. Два снятых среза остались в силе, потому что они сняты. Ряд оборвался не на моей стороне.
Снимать обе точки одним способом важнее, чем снять свежую. Если бы я в 2024-м обошёл сайт напрямую, а в 2026-м взял архив, любое расхождение пришлось бы объяснять разницей методов, и результат никого бы не убедил.
Ошибка очереди и ошибка отказа - разные вещи. «Достигнут предел активных заданий» означает «подожди», а «target server blocks access» означает «никогда». Скрипт, который не различает эти два случая, врёт дважды: сначала теряет половину данных, потом не замечает, что источник умер.
Формулировку результата надо держать рядом с кодом. Строка «считаются адреса карточек, а не судьбы компаний» живёт у меня прямо в документации скрипта. Через месяц, когда цифра попадёт в чужой текст, никто не вспомнит оговорку - а так она едет вместе с числом.
И последнее, уже не техническое. Когда витрина за два года обновляется на две трети, каталог франшиз перестаёт быть справочником и становится лентой. Читать его как каталог с историей - значит приписывать предложениям возраст, которого у них нет.
Данные разбора: 12 категорий, снимки 23 января 2024 года и 15 августа 2026 года, оба из веб-архива. Скрипты сбора, сравнения и заказа снимков лежат вместе с результатом - без них числа выше пришлось бы принимать на слово.