Форкнул last30days: заменил платный API на прямые запросы к Reddit через домашний пул прокси

Когда платный API становится дороже, чем хостить собственный пул прокси на домашнем сервере, уже не смешно. Я форкнул popular last30days скил и заменил ScrapeCreators на прямые запросы к Reddit через 32 прокси, работающих в round-robin с cooldown - и вот что из этого вышло.

Почему вообще форк

last30days - это Python-скил для Claude Code, который собирает данные с девяти платформ: Reddit, X/Twitter, YouTube, Hacker News, Polymarket, TikTok, Instagram, Bluesky и веб. У него больше 18 тысяч звёзд на GitHub, и я использую его почти каждый день для research.

Для Reddit скил тянул данные через ScrapeCreators - платный сервис scraping-as-a-service. Удобно, работает, но после нескольких месяцев регулярного использования счёт стал достаточно заметным, чтобы задуматься. К тому же стало интересно разобраться, как Reddit API устроен изнутри.

Reddit имеет публичный JSON API без OAuth. Просто добавь .json к любому URL - получишь данные. Поиск, посты, комментарии - всё доступно. Звучит просто, но есть нюанс: Reddit агрессивно лимитирует неавторизованные запросы. Один IP без ротации - и через несколько запросов получишь 429.

Решение очевидное: прокси. Их у меня уже было - 32 штуки на домашнем сервере, порты 3080-3111.

Как работает Reddit JSON API

База простая. Эндпоинт поиска выглядит так:

/search.json?q=claude+code&sort=relevance&t=month&limit=25&raw_json=1

Параметр raw_json=1 важен - он обходит часть bot-detection и возвращает данные без HTML-экранирования. Параметры sort принимают relevance, hot, top, new. Параметр t - временной фрейм: hour, day, week, month, year. Лимит до 100 постов за запрос.

Для комментариев - добавляешь .json к URL поста. Всё.

Проблема не в том, чтобы сделать один запрос. Проблема - делать их стабильно, без блокировок.

Архитектура пула прокси

В файле proxy_pool.py - класс ProxyPool с round-robin логикой и per-proxy cooldown. Работает так: каждый прокси получает запросы по очереди. Если прокси вернул 429 - он уходит на cooldown 30 секунд. Следующий запрос идёт к следующему доступному прокси.

Состояние пула сохраняется в JSON файл между запусками. Запустил скил утром - он знает, какие прокси горячие, какие на cooldown с прошлого раза. Не нужно ждать, пока пул прогреется заново.

Ротация по кругу выглядит примерно так:

Запрос 1  -> Прокси на порту 3080
Запрос 2  -> Прокси на порту 3081
...
Запрос 32 -> Прокси на порту 3111
Запрос 33 -> Прокси на порту 3080 (если прошло 30 сек)

Дополнительно - ротация User-Agent. Девять с лишним браузеров в пуле, меняются вместе с прокси. Reddit смотрит не только на IP.

Трёхуровневый fallback

Скил не ломается, если пул прокси недоступен. Три уровня:

  1. Запрос через пул прокси - основной путь
  2. Прямой запрос к public JSON - если прокси не работают, рискованно, но лучше чем ничего
  3. OpenAI для синтеза - если данных нет вообще, скил не вылетает с ошибкой

Третий уровень - это не источник свежих данных, а graceful degradation. Скил продолжает работать, даже если Reddit временно недоступен.

Как это встроилось в форк

Новые файлы: reddit_direct.py и proxy_pool.py. В существующих файлах - минимальные правки. Одна точка интеграции: замена вызова ScrapeCreators на мою функцию.

Это не случайно. Форки скилов должны быть узкими. Если переписать весь скил, merge с upstream превращается в боль. Если заменить только один компонент с явной точкой интеграции - конфликты будут только там. Когда mvanhorn выпустит следующую версию, синхронизировать будет просто.

ScrapeCreators в форке остался - для TikTok и Instagram. Там прямой scraping сложнее: JavaScript rendering, более тяжёлая защита. Там самостоятельная замена пока не оправдана.

Технические проблемы, которые пришлось решить

Мёртвые прокси. Некоторые прокси падают - перестают отвечать или возвращают ошибки подключения, а не 429. State persistence решает это: прокси помечается как dead, выпадает из ротации. Пул сам себя чистит.

Определение 429 vs реальная ошибка. Если сервер недоступен - это не cooldown, это проблема прокси. Разные коды ошибок ведут к разным action: 429 - cooldown на 30 секунд, connection error - прокси в dead list.

Параметр raw_json=1. Не документирован официально. Работает, снижает вероятность bot-detection. Но это недокументированное поведение - Reddit может изменить его без предупреждения. Комбинирую с User-Agent rotation как страховку.

Что получилось

Прямые запросы к Reddit оказались быстрее, чем через ScrapeCreators. Нет промежуточного сервера, нет overhead агрегатора. Reddit отвечает напрямую.

Стоимость - это стоимость прокси, которые у меня уже были. Reddit-часть больше не добавляет к счёту.

Зато добавился maintenance. Я вижу, что в пуле происходит, могу быстро фиксить - но нужно мониторить. В первые недели несколько прокси умерли, пул стабилизировался.

Честный дисклеймер

Использование прокси для обхода rate limiting может противоречить ToS Reddit. Я читал - там серая зона. JSON API публичен и задокументирован, но обход ограничений через прокси - не то, что Reddit явно разрешает.

Ещё риск: Reddit может усилить защиту или изменить API. Тогда придётся переписывать. Слежу за изменениями.

И ещё: subnet блокировки. Если Reddit заметит паттерн с одного диапазона IP - может прикрыть целый сегмент. Пока не столкнулся, но это реальный сценарий.


Форк живёт здесь: github.com/IGoRFonin/last30days. Если тебе не нравится, что скилы требуют платных API для работы с открытыми данными - вот схема, как это менять. Reddit стал первым шагом. Дальше можно делать то же с другими платформами, если хватит упорства на борьбу с их защитами.