오하아사 디스코드 알림 봇(1) - 간단 제작기

리벤쿤·2026년 3월 18일

사이드프로젝트

목록 보기
1/3
post-thumbnail

아침별점(おは朝星占い)

[Opinion] 우리는 왜 아침마다 오하아사를 열어 보게 될까

약 4년째, 게임과 서브컬처, 인터넷 방송이라는 취미를 공유하는 친목 커뮤니티에서 활동하고 있다. 오랫동안 인터넷 망령 생활을 해 온 수십 명의 사람들이 모여 있는 곳이다.

이곳에서 아침을 시작하는 루틴 중 하나는, 꽤 오랫동안 아침별점(오하아사, @Hi_Ohaasa)를 확인하는 것이다. 모르는 사람들에게 간단하게 설명하자면, 일본 아사히에서 만든 별자리 기반 운세 코너다.

국내에서는 X 계정을 통해 매일 별자리별 운세를 확인할 수 있다.

특이한 점이라면, 매일 별자리 별로 순위를 매겨서 보여준다는 것이다.

디스코드 봇 중 마냥으로 하루의 운세를 받아볼 수 있지만, 해당 X 계정처럼 순위를 보여주지는 않는다.

우리끼리는 이게 하루를 도파민을 느끼며 시작하는 콘텐츠인데, 매일 알림이 오도록 봇을 만들면 좋겠다는 생각을 하게 됐다.

홈페이지 구조 파악하기

기본적으로 해당 X 계정도 아침별점 홈페이지의 내용을 번역하여 게시된다.
우리에게 필요한 건 순위밖에 없으므로, 금방 만들 수 있을 것 같다는 생각이 들었다.

우선, 정보를 가져올 사이트의 구조를 파악하기로 한다.

개발자 도구를 이용해 html 구조를 살펴보니, oa_horoscope_list 아래로 클래스가 순서대로 나타나는 것을 확인할 수 있었다.
크롤링을 통해 해당 리스트의 순서를 가져오면 될 것 같다.

테스트 코드 작성하기

세팅 충돌을 최소화하기 위해, Playwright를 사용하기로 한다.

pip3 install playwright beautifulsoup4
python3 -m playwright install chromium

그리고 클래스 명으로 사용되는 별자리들의 영어 학명을 한글로 치환하기 위한 맵핑 테이블을 우선 설정해두자.

SIGN_MAP = {
    "aries": "양자리", "taurus": "황소자리", "gemini": "쌍둥이자리",
    "cancer": "게자리", "leo": "사자자리", "virgo": "처녀자리",
    "libra": "천칭자리", "scorpio": "전갈자리", "sagittarius": "사수자리",
    "capricorn": "염소자리", "aquarius": "물병자리", "pisces": "물고기자리"
}

크롤링을 통해 사이트의 html 코드를 가져오는 코드를 다음과 같이 작성한다.
item 개수가 12이면 성공이다.

from playwright.sync_api import sync_playwright
from bs4 import BeautifulSoup
import requests
import os

def run_local_crawling():
    url = "https://www.asahi.co.jp/ohaasa/week/horoscope/"

    # Playwright를 사용해 가상 브라우저 실행
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True) # 화면에 브라우저 창을 띄우지 않음
        page = browser.new_page()
            
        # 사이트 접속
        page.goto(url)
            
        # 핵심: 별자리 리스트(li)가 화면에 그려질 때까지 최대 10초 대기
        page.wait_for_selector('ul.oa_horoscope_list li', timeout=10000)
            
        # 자바스크립트 렌더링이 끝난 최종 HTML 코드를 가져옴
        html = page.content()
        browser.close()

    # 가져온 HTML을 BeautifulSoup으로 분석
    soup = BeautifulSoup(html, 'html.parser')
    horoscope_ul = soup.select_one('ul.oa_horoscope_list')
        
    if not horoscope_ul:
        print("❌ 데이터를 찾지 못했습니다.")
        return

    items = horoscope_ul.select('li')
    print(f"✅ 성공! 총 {len(items)}개의 데이터를 찾았습니다.\n")
     

다음은 포맷에 맞춰 별자리를 순위별로 출력하는 부분이다.

    # enumerate를 사용하여 1부터 차례대로 번호(index)를 매깁니다.
    for index, item in enumerate(items, start=1):
        classes = item.get('class', [])
            
        # 1. 별자리 영문명 및 한글명 추출
        english_sign = next((c for c in classes if c in SIGN_MAP), "unknown")
        korean_sign = SIGN_MAP.get(english_sign, english_sign)
            
        # 2. 순위 추출 (리스트의 순서 = 순위)
        rank_val = index
        rank_text = f"{rank_val}위"
            
        # 3. 이모지 설정
        if rank_val == 1:
            emoji = "🥇"
        elif rank_val == 2:
            emoji = "🥈"
        elif rank_val == 3:
            emoji = "🥉"
        else:
            emoji = "🔹"
            
            print(f"{emoji} {rank_text}: {korean_sign} ({english_sign})")
            
        print("-" * 30)

성공적으로 코드를 작성했다면, 로컬에서 다음과 같은 출력을 얻을 수 있다.

✅ 성공! 총 12개의 데이터를 찾았습니다.
------------------------------
🥇 1위: 양자리
🥈 2위: 사자자리
🥉 3위: 사수자리
🔹 4위: 쌍둥이자리
🔹 5위: 천칭자리
🔹 6위: 물병자리
🔹 7위: 황소자리
🔹 8위: 처녀자리
🔹 9위: 염소자리
🔹 10위: 게자리
🔹 11위: 전갈자리
🔹 12위: 물고기자리
------------------------------

GitHub Actions를 활용해 디스코드 웹후크로 연결

위 메세지를 디스코드로 보내는 함수 역시 작성해야 한다.
추후 깃허브 액션의 환경변수로 DISCORD_WEBHOOK를 설정해 실제 디스코드 채널의 웹후크 URL을 관리할 것이다.
기왕이면 예쁘게 payload 값에 사용자명과 프로필 사진까지 넣어보자.

def send_discord(message):
    webhook_url = os.environ.get('DISCORD_WEBHOOK')
    if not webhook_url:
        print("Webhook URL이 설정되지 않았습니다. 결과만 출력합니다.")
        print(message)
        return
    
    # 디스코드 봇 프로필 설정
    payload = {
        "username": "아침별점 요정",
        "avatar_url": "",
        "content": message
    }
    requests.post(webhook_url, json=payload)

깃허브 액션을 이용한 자동화 설정을 위해 .yml을 이용하도록 하자.

name: Ohaasa Daily Bot

on:
  schedule:
    # 한국 시간 기준 매일 오전 6시 실행 (UTC 기준 21시)
    - cron: '00 21 * * *'
  workflow_dispatch: # 수동으로 실행해볼 수 있는 버튼

jobs:
  run-bot:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.10'

      - name: Install dependencies
        run: |
          pip install playwright beautifulsoup4 requests
          
      - name: Install Playwright Browsers
        run: |
          playwright install chromium

      - name: Execute Script
        env:
          DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
        run: python main.py

리포지토리 구조는 다음과 같이 작성하면 될 것 같다.

[Repository]
├── .github               
│   └── workflows        
│       └── daily_bot.yml  # GitHub Actions 설정 파일
└── main.py                # 파이썬 크롤링 코드

레포지토리 설정에서 Secrets and variables > Actions > Repository secrets에서 새로운 항목을 추가한다.

디스코드 채팅 채널 > 설정을 통해 웹후크 URL을 받은 다음

DISCORD_WEBHOOK라는 이름으로, 내용은 웹후크 URL을 담아 Repository secret을 생성하면 된다.

결과물

레포지토리의 Actions 항목에서 액션을 선택, workflow를 작동시키면 수동으로 결과물을 확인할 수 있다.

GitHub Actions 특성상 첫 스케줄 할당에 시간이 꽤 소요된다고 한다. 그래서 트래픽을 피하기 위해 약간 애매한 시간으로 맞춰놓고, 지연을 최소화했다.

스케줄을 설정하고 하루가 지난 뒤, 정상적으로 설정한 시간대에 작동한 것을 확인했다.

깃허브 레포지토리 비로가기

profile
컴퓨터공학 & 미디어콘텐츠, AI/ML, HCI, PM, QA

0개의 댓글