Python : GitHub Actions와 크롤링 자동화 및 Telegram 알림 전송
GitHub Actions와 Python을 이용해 크롤링 자동화 및 Telegram 알림 전송
이 글에서는 GitHub Actions와 Python을 사용하여 웹 페이지에서 데이터를 크롤링하고, 그 결과를 Telegram을 통해 알림으로 전송하는 간단한 자동화 시스템을 구축하는 방법을 다룹니다. 특히, 1시간마다 자동으로 실행되도록 설정하는 방법과 GitHub Secrets를 통해 민감한 정보를 안전하게 처리하는 방법을 설명합니다.
1. 프로젝트 목표
우리의 목표는 특정 웹사이트에서 방 예약 정보를 크롤링하고, 예약 가능 자리가 생기면 Telegram 메시지로 알림을 보내는 시스템을 구축하는 것입니다. 이를 위해, GitHub Actions를 활용하여 1시간마다 Python 스크립트를 실행하도록 설정합니다.
2. GitHub Actions란?
GitHub Actions는 자동화된 작업을 설정할 수 있는 CI/CD 도구입니다. 이를 통해 코드 배포, 테스트, 빌드 및 기타 다양한 자동화를 수행할 수 있습니다. 우리는 GitHub Actions를 사용해 Python 스크립트를 1시간마다 실행하는 작업을 자동화할 것입니다.
3. Telegram API를 사용해 알림 보내기
Telegram에서 알림을 받기 위해서는 Telegram Bot API를 사용해야 합니다. 이 과정은 간단합니다:
- @BotFather로 Telegram 봇을 생성합니다.
- 봇 API 토큰을 얻고, 채팅 ID를 통해 메시지를 받을 사용자나 그룹을 설정합니다.
이후, Python의 requests
라이브러리를 통해 Telegram API로 메시지를 전송할 수 있습니다.
4. Python을 사용한 크롤러 작성
Python에서는 웹 페이지를 파싱하기 위해 BeautifulSoup 라이브러리를 사용할 수 있습니다. 이를 이용해 예약 가능한 방 정보를 추출하고, 자리 수가 1 이상인 경우 Telegram 메시지를 보낼 수 있도록 했습니다.
다음은 주요 Python 코드입니다:
def check_room_availability():
url = 'https://www.seocho.go.kr/site/ta/ex/tean/TeanFCalendar.do'
response = requests.get(url)
if response.status_code == 200:
soup = BeautifulSoup(response.content, 'html.parser')
messages = [] # 전송할 메시지를 저장할 리스트
tds = soup.find_all('td', class_='sat')
for td in tds:
date_span = td.find('span', class_='num')
if date_span and date_span.text.strip():
date = date_span.text.strip()
links = td.find_all('a')
for link in links:
room_type = link.text.strip()
if '4인실(온돌)' in room_type or '4인실(침대)' in room_type:
availability = int(room_type.split('(')[-1].split(')')[0])
if availability > 0:
message = f"{date}일 - {room_type.split('(')[0]} - ({availability})"
messages.append(message)
if messages:
full_message = "\n".join(messages)
send_telegram_message(full_message)
5. GitHub Actions로 1시간마다 스크립트 실행하기
GitHub Actions를 사용하여 스크립트를 1시간마다 실행하도록 설정하는 방법은 매우 간단합니다. 우리는 cron
표현식을 사용하여 1시간마다 Python 스크립트를 실행할 수 있습니다.
on:
schedule:
- cron: '0 * * * *' # 1시간마다 실행
이 설정을 통해 Python 스크립트가 매 시간 정각마다 실행됩니다.
6. GitHub Secrets로 민감 정보 관리
GitHub에서 Secrets는 중요한 정보(API 토큰, 비밀번호 등)를 안전하게 저장할 수 있는 기능입니다. 우리의 Python 스크립트는 Telegram API 토큰과 채팅 ID를 사용하기 때문에, 이러한 민감한 정보를 GitHub Secrets에 안전하게 저장하고 이를 워크플로우에서 참조합니다.
env:
TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
Python 코드에서는 이를 환경 변수로 가져옵니다:
TELEGRAM_TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT_ID = os.getenv('TELEGRAM_CHAT_ID')
7. 결론
이번 프로젝트를 통해 우리는 GitHub Actions와 Python을 사용하여 자동화된 크롤링 시스템을 구축하고, Telegram을 통해 예약 정보를 알림으로 받아볼 수 있게 했습니다. 이 작업을 통해 주기적인 스크립트 실행과 민감 정보 관리, 그리고 외부 API 통신까지 다양한 기술을 경험할 수 있었습니다.
GitHub Actions와 같은 도구를 사용하면 코드의 자동화와 배포, 그리고 기타 일상
적인 작업을 매우 쉽게 자동화할 수 있습니다.
최종 소스 코드
GitHub Actions를 사용하여 1시간마다 roomservice.py 스크립트를 실행하고, Telegram을 통해 예약 가능 여부를 알림으로 보내는 과정을 최종 정리한 코드입니다.
GitHub Actions Workflow (roomservice.yml)
name: Run roomservice.py every hour
on:
schedule:
# 1시간마다 실행 (cron 형식: 매 시간 정각에 실행)
- cron: '0 * * * *'
jobs:
run-roomservice:
runs-on: ubuntu-latest
steps:
# GitHub에서 코드를 체크아웃
- uses: actions/checkout@v2
# Python 3.x 설치
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
python-version: '3.x'
# 의존성 설치
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
# Chrome 및 ChromeDriver 설정
- name: Set up Chrome
uses: browser-actions/setup-chrome@v3
with:
chrome-version: stable
- name: Set up ChromeDriver
uses: nanasess/setup-chromedriver@v1
with:
version: latest # Chrome과 맞는 최신 버전 사용
# roomservice.py 스크립트 실행
- name: Run roomservice.py
run: |
python roomservice.py
env:
TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
roomservice.py
import os
import requests
from bs4 import BeautifulSoup
# 환경 변수에서 Telegram API 토큰과 Chat ID 가져오기
TELEGRAM_TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT_ID = os.getenv('TELEGRAM_CHAT_ID')
# 환경 변수가 없을 때 예외 처리
if TELEGRAM_TOKEN is None:
raise ValueError("TELEGRAM_TOKEN environment variable is not set")
if CHAT_ID is None:
raise ValueError("TELEGRAM_CHAT_ID environment variable is not set")
# Telegram 메시지 전송 함수
def send_telegram_message(message):
telegram_url = f"https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage"
payload = {
'chat_id': CHAT_ID,
'text': message
}
response = requests.post(telegram_url, data=payload)
if response.status_code == 200:
print("Message sent successfully")
else:
print(f"Failed to send message. Status code: {response.status_code}")
# 예약 가능 여부 확인 함수
def check_room_availability():
url = 'https://www.seocho.go.kr/site/ta/ex/tean/TeanFCalendar.do'
response = requests.get(url)
if response.status_code == 200:
soup = BeautifulSoup(response.content, 'html.parser')
messages = [] # 전송할 메시지를 저장할 리스트
# 토요일을 필터링하여 각 방의 정보를 처리
tds = soup.find_all('td', class_='sat')
for td in tds:
date_span = td.find('span', class_='num')
if date_span and date_span.text.strip():
date = date_span.text.strip()
links = td.find_all('a')
for link in links:
room_type = link.text.strip()
if '4인실(온돌)' in room_type or '4인실(침대)' in room_type:
availability = int(room_type.split('(')[-1].split(')')[0])
if availability > 0:
message = f"{date}일 - {room_type.split('(')[0]} - ({availability})"
messages.append(message)
if messages:
full_message = "\n".join(messages)
send_telegram_message(full_message)
else:
print(f"Failed to fetch data from {url}. Status code: {response.status_code}")
if __name__ == '__main__':
check_room_availability()
requirements.txt
requests
beautifulsoup4