클라우드 인프라 없이 로컬 퍼스트 Reddit 툴을 만든 방법
Source: Dev.to
음, 이 말이 뒤죽박죽하게 들릴 수도 있어요. 하지만 들어보세요.
저는 2주 동안 클라우드 기반 Reddit 스크레이퍼—인증, Postgres, 전체 기능을 모두 포함한—를 만들었지만, 그걸 모두 버리고 클라우드 인프라가 전혀 없는 데스크톱 앱으로 다시 시작했습니다. 이 프로젝트에서 제가 내린 최고의 결정이었어요. 이유는 다음과 같습니다.
클라우드 버전이 계속 차단당했다
저는 Reddit Toolbox라는 도구를 만들고 있습니다. 이 도구는 서브레딧을 스크랩하고 댓글 수에 따라 게시물을 필터링해 주며, Reddit 마케팅이나 연구에 유용합니다.
첫 번째 버전은 웹 앱이었습니다: Next.js 프론트엔드, VPS에 배포한 Python 백엔드, 인증 및 데이터를 위한 Supabase. 하지만 Reddit은 서버가 요청을 보내는 것을 정말 싫어합니다. 테스트를 시작한 지 불과 5분 만에 제 VPS IP가 차단되었습니다. 회전 프록시, 주거용 IP, 그리고 요청 속도 제한을 적용해도 안정적으로 해결되지 않았습니다. 해결했다고 생각할 때마다 Reddit이 탐지 방식을 업데이트해서 다시 처음부터 시작해야 했습니다. 사용자들은 “왜 차단당하나요?”라고 계속 물었지만, 저는 좋은 답변을 줄 수 없었습니다.
내가 계속 무시했던 명백한 해결책
A friend suggested, “Why don’t you just run it on the user’s machine?” I worried about distribution, manual updates, lack of usage tracking, and revenue models. But the fact remained: if the app runs from a home IP, Reddit sees a normal person browsing. No proxy tricks, no cat‑and‑mouse with detection—just works.
내가 다시 만든 것
웹 스택을 버리고 Python + PyQt6으로 새롭게 시작했습니다.
# core of the scraper – embarrassingly simple
import requests
import sqlite3
def scrape_subreddit(name, limit=100):
url = f"https://reddit.com/r/{name}.json?limit={limit}"
# Just a GET request from the user's IP.
response = requests.get(url, headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
})
if response.status_code == 200:
return response.json()['data']['children']
else:
# Fallback to RSS if JSON is blocked
return scrape_via_rss(name)
RSS 대체 옵션은 중요합니다—때때로 Reddit이 특정 패턴에 대해 JSON API를 차단하지만 RSS는 열어두기 때문에, 이 도구는 거의 절대 완전히 실패하지 않습니다.
데이터 저장에는 SQLite를 사용합니다—앱 옆에 존재하는 단일 파일입니다. 사용자는 해당 파일을 복사하여 백업할 수 있습니다. 데이터베이스 서버도 없고, 연결 문자열도 없으며, 새벽 2시에도 “내 DB가 실행 중인가?” 같은 디버깅을 할 필요가 없습니다.
나를 두렵게 만든 부분: 어떻게 돈을 벌까
웹 앱에서는 인증 뒤에 기능을 가두는 것이 쉽습니다. 데스크톱 앱의 경우 사용자가 바이너리를 다운로드하고, 크랙하거나, 패치를 적용하거나, 공유할 수 있습니다. DRM에 대해 너무 오래 고민했지만, 결국 $15/월 도구를 크랙할 사람들은 어차피 돈을 내지 않을 것이라는 사실을 깨달았습니다. 그래서 간단한 접근 방식을 선택했습니다:
- 앱은 세션당 한 번씩 Supabase API 호출을 통해 구독 상태를 확인하기 위해 서버에 연락합니다.
- 사용자가 오프라인이거나 호출을 차단하더라도 앱은 계속 작동하며, 무료 티어 제한(하루 15회 스크레이프)으로 기본 설정됩니다.
누군가 이를 우회할 수 있을까요? 물론 가능합니다. 제가 신경 쓰나요? 별로요. 유료 고객은 만족하고, 나머지는 어차피 고객이 되지 않을 사람들입니다.
내가 수용한 트레이드오프
- No cross‑device sync. 데이터가 한 대의 컴퓨터에만 존재합니다; 다른 기기에서는 내보내기/가져오기가 필요합니다. 약간 불편하지만 대부분의 사용자는 한 대의 컴퓨터에서 작업합니다.
- Manual updates. 자동 업데이트 프로그램을 개발 중이지만, 현재는 사용자가 직접 새 버전을 다운로드합니다. 일부 피드백에 따르면 사람들은 소프트웨어가 언제 바뀌는지 정확히 아는 것을 선호하기도 합니다.
- Zero telemetry. 사용자가 앱을 어떻게 사용하는지에 대한 정보를 전혀 수집하지 않습니다. 나중에 선택적 분석을 추가할 수도 있지만, 대시보드에 파묻히지 않는 것이 좋습니다.
몇 주 후 결과
- 차단에 관한 지원 티켓이 전혀 없음. 웹 버전은 매일 티켓이 생성됐지만 로컬 버전은 그렇지 않음.
- 앱 크기가 약 50 MB. Electron 버전은 ~150 MB 이상이 될 것이고, PyQt6은 네이티브하고 가벼운 느낌임.
- 긍정적인 사용자 피드백. 사용자는 간단함을 높이 평가—가입 절차가 필요 없음. 한 이메일에서는 “드디어 시도하기 전에 내 이메일을 요구하지 않는 도구가 나왔구나.” 라고 했음. 그 말에 큰 힘을 얻음.
로컬‑퍼스트를 언제 선택할까
로컬‑퍼스트가 모든 경우에 적합한 것은 아닙니다. 여전히 서버가 필요한 경우는 다음과 같습니다:
- 실시간 협업
- 디바이스 간 동기화가 가능한 모바일 앱
- 소셜 기능이 포함된 모든 것
하지만 외부 API와 통신하는 단일 사용자 생산성 도구—특히 스크래퍼 방지를 적극적으로 하는 API—의 경우, 로컬‑퍼스트를 사용하면 불필요한 클라우드 복잡성을 없앨 수 있습니다.
제가 만든 것을 보고 싶다면 Reddit Toolbox라는 이름입니다. “Reddit Toolbox wappkit”을 검색하거나 wappkit.com을 확인해 보세요. 무료 티어가 제공됩니다.
PyQt, 아키텍처, 혹은 제가 이제 프록시를 싫어하게 된 이유 등에 대한 질문에 기꺼이 답변해 드리겠습니다.