공고 알림봇 만들기 (10편) — Reddit이 API를 막아서 RSS로 우회했습니다
결론부터: Reddit JSON API는 2023년부터 인증 없이 쓰면 403이 옵니다. 그런데 RSS 피드(/r/서브레딧/new.rss)는 아직 인증 없이 열려 있습니다. 단, User-Agent를 보내야 하고 호출 간격을 넉넉히 둬야 합니다.
9편에서 로컬 LLM으로 걸러내는 걸 붙였죠. 그런데 그 앞단, 글을 가져오는 쪽에서 먼저 막혔던 얘기를 안 했네요.
지난 편 → 9편 — LM Studio 로컬 LLM으로 수집 결과를 걸렀습니다
문서대로 했는데 403이 왔습니다
Reddit에서 글 목록을 가져오는 방법은 검색하면 금방 나옵니다. 주소 끝에 .json을 붙이면 JSON으로 받을 수 있다는 거죠.
옛날에는 그랬습니다. 지금은 403이 옵니다.
2023년에 Reddit이 API 정책을 바꾸면서 인증 없는 접근을 막았어요. 앱을 등록하고 OAuth 인증을 붙여야 합니다. 검색으로 나오는 예제 코드 상당수가 그 이전에 쓰인 것이라, 그대로 따라 하면 안 됩니다.
여기서 선택지가 갈렸어요.
| 방법 | 비용 |
|---|---|
| OAuth 인증 붙이기 | 앱 등록 + 토큰 갱신 로직 |
| 스크래핑 | HTML 구조 바뀌면 매번 깨짐 |
| RSS 피드 | 인증 없음 |
RSS는 아직 열려 있었습니다
Reddit은 오래전부터 RSS를 제공해왔고, 그게 아직 살아 있습니다.
https://www.reddit.com/r/서브레딧이름/new.rss
이걸 부르면 최신 글 목록이 Atom 형식 XML로 옵니다. 인증이 필요 없어요.
4편에서 K-Startup이 XML을 준다고 했는데, 여기서 또 XML을 만났습니다. 다만 이쪽은 표준 Atom 형식이라 훨씬 다루기 쉬웠어요. 글마다 제목·링크·본문이 정해진 자리에 들어 있습니다.
막혔다고 포기하지 않고 다른 문을 찾은 게 이 편의 핵심입니다. 정문이 잠겼어도 옆문이 열려 있을 수 있어요.
사람인 척은 해야 합니다
인증은 필요 없지만 조건이 하나 있었어요. User-Agent를 보내야 합니다.
이건 "나는 어떤 프로그램입니다" 하고 알리는 값인데, 안 보내거나 기본값으로 두면 막힙니다. Reddit이 권장하는 형식이 있어서 그대로 맞췄어요.
python:SBNotifier:v1.0 (by /u/사용자명)
무엇을 만든 누구인지 밝히는 형식입니다. 차단하려면 차단하라는 뜻이기도 하죠. 숨기고 우회하는 것보다 이게 낫다고 봤습니다.
본문에 HTML이 섞여 있었습니다
RSS로 받은 본문은 HTML 태그가 그대로 들어 있습니다. 사람이 읽을 화면용이니 당연한데, 저는 텍스트만 필요했어요.
그냥 넘기면 LLM이 태그까지 읽고 판단합니다. 그래서 태그를 지우고, & 같은 기호를 원래 글자로 되돌린 다음, 300자로 잘라서 넘겼어요.
자른 이유는 판단에 필요한 만큼만 주면 되기 때문입니다. 긴 글을 통째로 넣으면 로컬 모델이 느려지고, 정작 핵심은 앞부분에 있는 경우가 많았어요.
⚠️ 그런데 절반만 성공했습니다
여기가 이 편에서 가장 솔직해야 할 부분입니다. 우회는 됐지만 완전히 풀리진 않았어요.
서브레딧 다섯 개를 순서대로 부르는데, 로그를 세어보니 이렇습니다.
| 서브레딧 | 429(과다호출) 발생 |
|---|---|
| r/androidapps | 2회 |
| r/iosapps | 262회 |
| r/AppIdeas | 325회 |
| r/startups | 326회 |
| r/SideProject | 325회 |
첫 번째만 통과하고 나머지 넷은 거의 매번 막힙니다. 호출 사이에 2초를 쉬게 해뒀는데 그게 부족한 거예요.
결과가 이렇게 나왔습니다.
r/androidapps → 알림 46건 r/iosapps → 3건 r/AppIdeas → 2건 r/startups → 0건 r/SideProject → 0건
다섯 개를 붙였는데 실질적으로 하나만 일하고 있습니다.
왜 아직 안 고쳤나
이유는 두 가지예요.
① 봇이 죽지 않기 때문입니다. 429가 오면 그 서브레딧만 건너뛰고 다음으로 갑니다. 하나가 막혀도 전체가 멈추지 않게 짜뒀어요. 그래서 눈에 안 띄었습니다. 로그에 경고는 찍히는데, 알림은 계속 오니까 "돌아가고 있네" 하고 넘어갔죠.
② 아이디어 발굴은 급하지 않았습니다. 이 봇의 본업은 공고 알림이고, 아이디어 쪽은 덤이에요. 급한 것부터 하다 보니 밀렸습니다.
고칠 방법은 어렵지 않습니다. 쉬는 시간을 늘리거나, 서브레딧을 사이클마다 하나씩 돌려가며 부르면 됩니다. 한 시간에 한 번 도는 봇이니 5분씩 쉬어도 상관없어요.
이번에 글을 쓰면서 로그를 세어보고 처음 알았습니다. 블로그를 쓰는 게 점검이 된 셈이에요.
정리 — 남의 서비스는 언제든 문을 닫는다
이 편의 교훈은 이렇습니다.
외부 API는 내 것이 아닙니다. 어제 되던 게 오늘 막힐 수 있어요. Reddit은 정책을 바꿨고, 제가 할 수 있는 건 다른 문을 찾는 것뿐이었습니다.
그래서 소스마다 파일을 따로 둔 게 여기서 값을 했어요(4편). Reddit 쪽이 막혀도 공고 수집기들은 아무 영향이 없었습니다. 한 소스가 죽어도 나머지가 도는 구조였던 거죠.
그리고 하나 더 — 조용히 절반만 성공하는 상태가 있다는 걸 알았습니다. 완전히 죽으면 알아채는데, 부분적으로 죽으면 모르고 넘어가요. 6편·9편에서도 같은 종류였습니다. 이 시리즈에서 세 번째로 만난 함정이네요.
다음 편
이제 마지막입니다. 두 달 넘게 돌린 이 봇이 실제로 제 결정을 바꾼 날의 이야기로 마무리하겠습니다. → 11편·완결 — 봇이 알려준 공고로 이사를 검토했습니다
댓글
댓글 쓰기