전장연 알리미
만약에 모든 지하철 호선을 타도 출근 시간이 똑같다면 어떤 지하철을 탈 것인가?
"음.. 곧 도착하는 지하철을 먼저 타지 않을까요?
맞는 말이다. 물론 전장연 아침 지하철 승하차 시위가 일어나기 전 까지는 말이다.
그렇다면 정답은
"시위를 하지 않는 호선의 지하철을 타는 것" 이, 지금 시대에 정답이다.
며칠 전까지 사당에서 출근해서 2호선과 4호선 중에 4호선만 고집하다 출근이 늦어진 나 때문에 만든 게 아니라고 절대 말하지 않는다.
프로세스
- 스크랩한다.
- 나에게 메시지를 보낸다.
전혀 어렵지 않은 코드와 단순한 과정만 있을 뿐이다.
확인해야 할 사항
- 지하철 시위 및 지연과 같은 안내는 서울 도로 교통 공사홈페이지 공지사항에서 확인 가능
- 시위전날에 공지가 올라옴
- 최신 글 하나만 확인, BUT 'NOTICE' 경우에 그림 1처럼 항상 상단에 위치함
- 그림 2처럼, 날짜가 범위로 된 경우가 있음
- 게시글을 클릭하면, 그림 3으로 넘어가서 자세한 내용 확인 가능
- 카카오 액세스 토큰 발급받기(이게 제일 귀찮은..)
결과
- 물론 전 날 공지가 없으면 없다고 보내주긴 한다.
코드
- 코드는 주석을 달아 두겠습니다.
import requests
from bs4 import BeautifulSoup as bs
from datetime import datetime, timedelta
from collections import defaultdict
import json
# 서울도로 교통공사 메인 주소
seoul_metro_home_url = 'http://www.seoulmetro.co.kr/kr/'
# 공지사항
announcement_page = 'board.do?menuIdx=546'
# 공지사항 게시글 selector path
announcement_selector = '#contents > div.tbl-box1 > table > tbody'
# 그림 3의 내용에 해당하는 selector path
detail_selector = '#board-top > article > div > table > tbody > tr:nth-child(3) > td > div.textarea-area > article > div'
# 글 제목에서 찾을 단어들
# 사실 '열차운행 지연 예정 및 무정차 통과 안내' 라고 고정되어 있는 것 같기도..
words_to_check = ['지연', '무정차']
# 전 날 지연 관련 공지 없을 때, 리턴할 메시지
is_no_notice_msg = '알림 없음'
# 날짜 형식이 1/4~1/6인 경우, 1/4, 1/5, 1/6 을 찾기 위함
def date_range(start, end):
start = datetime.strptime(start, "%m/%d")
end = datetime.strptime(end, "%m/%d")
dates = [(start + timedelta(days=i)).strftime("%m/%d") for i in range((end - start).days + 1)]
return dates
# 리턴 값은 Bool, 오늘 날짜에 해당하는 공지가 있는 지 확인하기 위함
def check_noticed_of_today(date_string):
today = datetime.today().strftime('%m/%d')
try:
if "~" in date_string:
start, end = tuple(map(lambda d: d.strip(), date_string.split('~')))
dates = date_range(start, end)
if today in dates:
return True
else:
notice_date = datetime.strptime(date_string, "%m/%d").strftime('%m/%d')
if today == notice_date:
return True
except ValueError as e:
print(e)
#
def get_response_body(url, selector_path):
response = requests.get(url)
if response.status_code != 200:
raise Exception('Check Response')
html = response.text
soup = bs(html, 'html.parser')
tbody = soup.select_one(selector_path)
return tbody
if __name__ == "__main__":
return_msg = defaultdict()
url = seoul_metro_home_url+announcement_page
tbody = get_response_body(url, announcement_selector)
# 태그 종류는 직접 찾아야함
tr_lists = tbody.select('tr')
# NOTICE 인 경우, 제외
# 지연 안내가 NOTICE로 올라 올 수도 있는데, 일단 제외
for tr in tr_lists:
content = tr.select('td')
text_number = content[0].get_text()
if text_number.isdigit(): break
# 글 제목과 그림 3으로 넘어가는 주소(href)
content_body = content[1].select_one('a')
href = content_body.attrs['href']
title = content_body.attrs['title']
# 글 제목에서 날짜 가져옴. 정규식 XX
date_string = title.rsplit('(')[-1].replace(")", "")
# 오늘 날짜 공지 & 무정차, 지연 단어 있는 경우 스크랩
if check_noticed_of_today(date_string) and any(word in title for word in words_to_check):
url = seoul_metro_home_url + href
tbody = get_response_body(url, detail_selector)
return_msg['title'] = title
return_msg['body'] = tbody.get_text()
else:
return_msg['title'] = is_no_notice_msg
return_msg['body'] = is_no_notice_msg
# 나에게 메시지 보내기
response = requests.post(kakao_url, headers=headers, data=data)
이제 스케줄링 툴에 올려서 매일 알림을 받아야지. 끝이다~
라고 했지만, 그 발언 때문인지
다음날 일어나서 보니 토큰은 만료된다는 사실을 까먹고 있었..
결론
- 1편으로 끝내려던 게 갑자기 2편으로..
'MLOps > Development' 카테고리의 다른 글
Dag를 알고 있는 녀석은?(K8sExecutor & K8sPodOperator) (0) | 2023.03.21 |
---|---|
효율적인 대규모 크롤링 시스템 운영을 위한 Fargate on EKS 적용하기 - 2편 (2) | 2023.03.09 |
효율적인 대규모 크롤링 시스템 운영을 위한 Fargate on EKS 적용하기 - 1편 (2) | 2023.02.25 |
[티끌모아 빅데이터] 나의 방문 일지 - 제 1편 : 티끌의 시작 (0) | 2023.02.17 |
전장연 알리미 (feat. 지하철 뭐 안타지?) - 2 (2) | 2023.01.11 |