RSS로 내 글이 실제로 올라갔는지 자동 확인하기 — 파이썬 표준 라이브러리만으로

예약 발행을 걸어두면 “내일 아침에 알아서 올라가겠지” 하고 잊게 됩니다. 이 블로그도 매일 오전 9시 예약 발행으로 운영하는데, 이번에 RSS 피드로 최근 7일치 발행을 자동 확인하는 스크립트를 만들어 직접 돌려보니 7일 중 이틀이 비어 있었습니다. 하루는 자동화를 데스크탑에서 노트북으로 옮기는 동안 예약 큐가 비어 생긴 공백이었습니다. 관리 화면을 매일 열어보지 않는 한 이런 공백은 잘 보이지 않습니다. 이번 글에서는 파이썬 표준 라이브러리만으로 RSS 발행 확인 자동화를 만들면서 실제로 부딪힌 오류와, 피드 날짜를 다룰 때 놓치기 쉬운 시간대 함정까지 정리합니다.

왜 RSS로 확인하나

발행 여부를 확인하는 방법은 여러 가지가 있지만, RSS 피드는 그중 가장 부담이 적습니다.

방법로그인준비물확인되는 것
관리 화면 직접 열기필요없음전부 (하지만 매일 사람이 해야 함)
REST API 조회예약·초안까지 보려면 필요애플리케이션 비밀번호예약 대기 글까지
RSS 피드불필요피드 주소 하나독자에게 실제로 공개된 글

핵심은 마지막 열입니다. RSS에는 공개된 글만 나옵니다. 예약은 걸려 있지만 실제로는 안 나간 글, 초안으로 남아버린 글은 피드에 없습니다. “독자 입장에서 정말 올라갔는가”를 확인하려는 목적에는 오히려 이 점이 장점입니다. 워드프레스는 /feed/ 주소로 피드를 기본 제공하므로 따로 설정할 것도 없습니다.

첫 시도: 406 Not Acceptable

처음에는 가장 단순하게 짰습니다. 외부 패키지 없이 urllib로 피드를 받고 xml.etree로 항목을 꺼내는 코드입니다.

import urllib.request
import xml.etree.ElementTree as ET

FEED = "https://codetipbox.com/feed/"

with urllib.request.urlopen(FEED, timeout=15) as r:
    data = r.read()

root = ET.fromstring(data)
for item in root.iter("item"):
    print(item.findtext("pubDate"), "|", item.findtext("title"))

그런데 이 블로그 피드에 실제로 돌려보니 바로 실패했습니다.

  File "...\urllib\request.py", line 639, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 406: Not Acceptable

브라우저로 같은 주소를 열면 멀쩡히 보이는데 스크립트만 거절당한 겁니다. 차이는 요청에 붙는 User-Agent였습니다. urllib는 따로 지정하지 않으면 Python-urllib/3.12 같은 값을 보내는데, 보안 설정이 걸린 사이트는 이런 요청을 봇으로 보고 막는 경우가 많습니다. 이 블로그도 앞단에 봇 차단이 걸려 있어서, 발행 자동화를 만들 때도 같은 이유로 요청 방식을 바꿔야 했던 적이 있습니다.

User-Agent를 붙이니 200

요청 객체를 만들어 브라우저와 같은 User-Agent를 붙이면 됩니다. 바뀌는 부분만 보면 이렇습니다.

UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0 Safari/537.36"

req = urllib.request.Request(FEED, headers={"User-Agent": UA})
with urllib.request.urlopen(req, timeout=15) as r:
    print("HTTP", r.status, r.headers.get("Content-Type"))
    data = r.read()

다시 실행한 결과입니다. 응답 시간은 2초 남짓이었습니다.

HTTP 200 application/rss+xml; charset=UTF-8
items: 10
Wed, 07 Oct 2026 01:40:19 +0000 | 예약 발행이 엉뚱한 시각에 나갈 때 — 타임존 점검 순서 5단계
Mon, 05 Oct 2026 00:00:00 +0000 | 문서 중복도 측정으로 AI가 쓴 글이 서로 얼마나 겹치는지 재보기 (n-gram 유사도)
Sun, 04 Oct 2026 02:05:19 +0000 | 스크립트 로그 관리 — 실행 로그를 날짜별로 남기고 오래된 건 자동 삭제하기

피드는 정상으로 받아졌고 항목은 10개였습니다. 워드프레스 피드는 기본적으로 최근 글 10개만 담기 때문에, 하루 한 편 발행이라면 열흘 남짓까지 거슬러 볼 수 있습니다. 더 길게 보려면 관리 화면의 설정 → 읽기에서 피드에 표시할 글 수를 늘리면 됩니다.

남의 사이트 피드를 수집할 때는 이용 약관과 robots.txt를 먼저 확인하세요. 이 글의 스크립트는 하루 한 번 내 블로그 피드를 읽는 용도라 부담이 없지만, 짧은 간격으로 반복 요청하면 차단 대상이 됩니다.

함정: pubDate는 UTC입니다

출력을 다시 보면 맨 위 글의 시각이 01:40:19 +0000입니다. 이 글은 한국 시각 오전 10시 40분에 공개됐는데, 피드에는 UTC 기준으로 찍혀 있습니다. 오전 9시 예약 글들은 전부 00:00:00 +0000으로 나옵니다.

이 날짜를 그대로 잘라서 비교하면 문제가 생깁니다. 한국 시각 0시~9시 사이에 공개된 글은 UTC로는 전날이라서, “오늘 글이 없다”고 잘못 판단합니다. 그래서 날짜 문자열을 email.utils.parsedate_to_datetime으로 시간대 정보까지 살려서 읽고, 한국 시각으로 변환한 다음에 날짜를 비교해야 합니다. RSS의 pubDate는 이메일 헤더와 같은 형식(RFC 822 계열)이라 이 함수가 그대로 맞습니다.

완성 스크립트: 최근 7일 빈 날 점검

위 내용을 합쳐서, 최근 7일 각각에 공개된 글이 있는지 한국 시각 기준으로 확인하는 스크립트입니다. 외부 패키지가 필요 없어서 파이썬만 깔려 있으면 바로 돌아갑니다.

import sys
import urllib.request
import xml.etree.ElementTree as ET
from datetime import datetime, timedelta, timezone
from email.utils import parsedate_to_datetime

FEED = "https://codetipbox.com/feed/"   # 내 블로그 피드 주소로 바꾸세요
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0 Safari/537.36"
KST = timezone(timedelta(hours=9))   # 한국은 서머타임이 없어 고정 오프셋으로 충분합니다
DAYS = 7                             # 최근 며칠을 점검할지


def fetch_items(url):
    req = urllib.request.Request(url, headers={"User-Agent": UA})
    with urllib.request.urlopen(req, timeout=15) as r:
        root = ET.fromstring(r.read())
    items = []
    for it in root.iter("item"):
        # pubDate는 UTC(+0000)로 오므로 한국 시각으로 바꿔야 날짜가 맞습니다
        published = parsedate_to_datetime(it.findtext("pubDate")).astimezone(KST)
        items.append((published, it.findtext("title"), it.findtext("link")))
    return items


def main():
    items = fetch_items(FEED)
    today = datetime.now(KST).date()
    by_day = {}
    for published, title, link in items:
        by_day.setdefault(published.date(), []).append((published, title))

    print("피드 항목", len(items), "개 / 기준일", today, "(KST)")
    missing = []
    for i in range(DAYS):
        day = today - timedelta(days=i)
        posts = by_day.get(day)
        if posts:
            for published, title in posts:
                print("  OK  ", day, published.strftime("%H:%M"), title)
        else:
            print("  없음", day)
            missing.append(day)

    if today in missing:
        print("오늘 글이 아직 피드에 없습니다.")
        sys.exit(1)        # 스케줄러·CI에서 실패로 잡히도록
    if missing:
        print("최근", DAYS, "일 중 빈 날:", ", ".join(str(d) for d in missing))


if __name__ == "__main__":
    main()

이 블로그에 실제로 돌린 결과입니다. 실행 시간은 약 2초였습니다.

피드 항목 10 개 / 기준일 2026-10-07 (KST)
  OK   2026-10-07 10:40 예약 발행이 엉뚱한 시각에 나갈 때 — 타임존 점검 순서 5단계
  없음 2026-10-06
  OK   2026-10-05 09:00 문서 중복도 측정으로 AI가 쓴 글이 서로 얼마나 겹치는지 재보기 (n-gram 유사도)
  OK   2026-10-04 11:05 스크립트 로그 관리 — 실행 로그를 날짜별로 남기고 오래된 건 자동 삭제하기
  없음 2026-10-03
  OK   2026-10-02 09:00 PC를 정해진 시각에 깨우고 재우는 자동화
  OK   2026-10-01 09:00 Node.js에서 .cmd 실행이 EINVAL로 죽을 때 (윈도우)
최근 7 일 중 빈 날: 2026-10-06, 2026-10-03

도입부에서 말한 이틀이 여기서 드러났습니다. 10월 6일은 자동화를 옮기는 과정에서 예약 큐가 비어 있던 날이고, 10월 3일도 비어 있었습니다. 덤으로 하나 더 보였는데, 10월 4일 글은 평소 예약 시각인 9시가 아니라 11시 5분에 공개돼 있었습니다. 날짜만 확인하는 스크립트였지만 시각까지 같이 찍게 해두니 이런 이상도 함께 잡힙니다.

오늘 글이 없으면 실패로 끝내기

자동 점검의 핵심은 문제가 있을 때 시끄럽게 실패하는 것입니다. 위 스크립트는 오늘 날짜의 글이 없으면 종료 코드 1로 끝납니다. 기준일을 글이 없던 10월 6일로 고정해서 실패 경로도 확인했습니다.

피드 항목 10 개 / 기준일 2026-10-06 (KST)
  없음 2026-10-06
  OK   2026-10-05 09:00 문서 중복도 측정으로 AI가 쓴 글이 서로 얼마나 겹치는지 재보기 (n-gram 유사도)
  ...
오늘 글이 아직 피드에 없습니다.
(종료 코드 1)

종료 코드가 0이 아니면 작업 스케줄러는 “마지막 실행 결과”에 오류 코드를 남기고, GitHub Actions 같은 CI는 작업을 빨간색 실패로 표시합니다. 메일이나 메신저 알림을 붙이지 않아도 최소한 기록에는 남는다는 뜻입니다. 알림까지 받고 싶다면 sys.exit(1) 바로 앞에 웹훅 호출 한 줄을 넣으면 됩니다.

매일 자동으로 돌리기

윈도우라면 작업 스케줄러에 등록합니다. 예약 발행 시각(오전 9시)보다 조금 뒤로 잡아야 그날 글이 공개된 뒤에 확인합니다.

schtasks /Create /TN "rss-publish-check" /SC DAILY /ST 10:00 ^
  /TR "python C:\scripts\check_rss.py"

리눅스 서버나 CI에서 돌린다면 시간대에 주의하세요. 클라우드 서버와 GitHub Actions의 스케줄은 기본적으로 UTC 기준이라, 한국 시각 오전 10시에 돌리려면 UTC 오전 1시로 적어야 합니다. 스크립트 자체는 KST로 날짜를 계산하므로 서버 시계가 UTC여도 판단 결과는 같습니다.

정리

  1. RSS 피드에는 공개된 글만 나오므로 “실제로 올라갔는가”를 확인하기에 적합합니다.
  2. urllib 기본 User-Agent는 봇으로 막힐 수 있습니다. 406·403이 나오면 User-Agent부터 의심하세요.
  3. pubDate는 UTC입니다. parsedate_to_datetime으로 읽고 한국 시각으로 바꾼 뒤 날짜를 비교합니다.
  4. 오늘 글이 없으면 종료 코드 1로 끝내서 스케줄러·CI에 실패로 남깁니다.

지금 바로 해볼 수 있는 가장 작은 일은 위 스크립트의 FEED 주소만 내 블로그로 바꿔 한 번 실행해보는 것입니다. 2초면 결과가 나오고, 저처럼 생각지 못한 빈 날이 보일 수도 있습니다.

다음 글에서는 이런 점검 스크립트가 여러 개로 늘어났을 때, 돌아가는 자동화들을 한 번에 점검하는 헬스체크 스크립트로 묶는 방법을 다루겠습니다.

댓글 남기기