[Python] 구글 Open API로 캘린더 활용해보기 3 (크롤링 + 일정 추가, 삭제)

hukim·2022년 5월 22일
0

Open API

목록 보기
3/11
post-thumbnail

📆 크롤링해서 구글 Open API로 캘린더에 일정 추가하기

저번 포스팅에 이어서 이번에는 특정 페이지를 크롤링한 후 이 데이터를 캘린더에 추가해보고 삭제까지 진행해보았다.

이번에 크롤링 할 사이트는 KBO(프로야구)의 일정 중 '기아타이거즈' 팀의 일정을 크롤링 해보았다.

⚾️ 타이거즈 경기 긁어오기

크롤링은 BeatuifulSoup, Selenium을 이용하여 진행했다. (참고한 블로그)

크롬 웹 드라이버

이전에 크롬 웹 드라이버를 사용했던 적이 있어서 그때 사용한 크롬 웹 드라이버를 그대로 썼더니 오류가 발생했다.

  1. 권한 문제
  2. 윈도우 버전 파일 사용

이전에 윈도우OS에서 작업하던 파일을 그대로 가져다 쓰다보니 오류가 났다. 이 경우 맥버전을 다시 다운로드 해주면 된다.

위 오류에 관한 해결방법은 링크된 블로그에 친절히 나와있다.

기아타이거즈 경기 선택

# 정규 시즌 콤보 박스 클릭
driver.find_element(by=By.XPATH, value="//select[@id='ddlSeries']/option[text()='KBO 정규시즌 일정']").click()

왼쪽에 보이는 콤보박스에 각각 시범경기, 정규시즌, 포스트시즌 일정이 있다.
이번엔 정규시즌 일정을 가져올 예정이므로 ddlSeries로 되어있는 id 값을 이용해 콤보박스를 정규시즌으로 설정해준다.

# 기아 선택
driver.find_element(by=By.XPATH, value="//ul[@class='tab-schedule']/li[@attr-value = 'HT']").click()

그리고 KIA의 일정만 보기 위해서 팀 선택을 해준다.
단, 옛 구단이름인 해태에서 나온것으로 보이는 HT로 되어있는 부분을 주의한다.(아직도..? 🫢)

전체 코드

def convert_date(game_date: str):
    month = int(game_date[0:2])
    day = int(game_date[3:5])
    return {"month": month, "day": day}

def convert_team_data(team_data: str):
    team_data = team_data.replace("vs", " vs ")
    return "".join(re.compile("[^0-9]").findall(team_data))
    
def crawling_kia_tigers():
    driver = webdriver.Chrome("./chromedriver")
    driver.get('https://www.koreabaseball.com/Schedule/Schedule.aspx')

    # 정규 시즌 콤보 박스 클릭
    driver.find_element(by=By.XPATH, value="//select[@id='ddlSeries']/option[text()='KBO 정규시즌 일정']").click()

    # 기아 선택
    driver.find_element(by=By.XPATH, value="//ul[@class='tab-schedule']/li[@attr-value = 'HT']").click()
	
    month_list = ['05']
    schedule_list = []

    for month in month_list:
        # 달력 선택
        driver.find_element(by=By.XPATH, value="//select[@id='ddlMonth']/option[text()='"+str(month)+"']").click()
        # 결과
        html = driver.page_source
        soup = BeautifulSoup(html, 'html.parser')
        table = soup.find('table', {'class': 'tbl'})
        trs = table.find_all('tr')

        for idx, tr in enumerate(trs):
            if idx > 0:
                tds = tr.find_all('td')
                # tds[0] 날짜, tds[1] 시간, tds[2] 팀 + 스코어, tds[7] 장소
                date = convert_date(tds[0].text.strip())
                schedule_info = {
                    "date": tds[0].text.strip(),
                    "month": date["month"],
                    "day": date["day"],
                    "begin_time": tds[1].text.strip(),
                    "end_time": f"{(int(tds[1].text.strip()[0:2]) + 3)}:{tds[1].text.strip()[3:5]}",
                    "team": convert_team_data(tds[2].text.strip()),
                    "stadium": tds[7].text.strip(),
                }
                schedule_list.append(schedule_info)

    driver.close()
    return schedule_list

일정을 가져온 다음 구글 캘린더에 일정을 추가해야되는 부분을 생각하여 그에 맞춰 데이터를
schedule_info에 정리해서 담아준다.

월, 일을 구분하기 위하여 따로 month,day에 나눠서 담아주고,
홈페이지엔 시작시간만 기본적으로 제공하는데 (야구는 시간이 정해진 스포츠가 아니기 때문)
대략 3시간으로 끝나는 시간을 잡아서 end_time에 넣어줬다.

그리고 tds[2]에서 가져오는 데이터는 팀vs팀 형태로 나오는데 아직 경기를 치르지 않은 경우는
KIAvsNC 이런 형태로 나오지만 이미 경기를 치뤄서 스코어가 나와있는 경우엔
KIA13vs2한화 의 형태로 가져오게 되어서 스코어는 삭제처리하게끔 하였다.

📅 크롤링한 데이터를 구글 캘린더에 추가

def set_game_schedule(schedule_list: list):
    google_calendar = GoogleCalendar()

    for schedule in schedule_list:
        date = datetime.date(year=2022, month=schedule["month"], day=schedule["day"]).isoformat()
        event = {
            "summary": schedule["team"],  # 일정 제목
            "location": schedule["stadium"],  # 일정 장소
            "description": '야구 경기',  # 일정 설명
            "start": {  # 시작 날짜
                "dateTime": date + f"T{schedule['begin_time']}:00",
                "timeZone": "Asia/Seoul",
            },
            "end": {  # 종료 날짜
                "dateTime": date + f"T{schedule['end_time']}:59",
                "timeZone": "Asia/Seoul",
            },
        }

        google_calendar.set_google_calendar(event)

크롤링한 데이터를 가져와서 캘린더에 반복문으로 추가해준다.
생각보다 추가하는데 시간이 꽤 걸린다. 그래서 시즌 전체 일정을 추가하려고 하였으나 5월 일정만 추가하였다.
(위의 크롤링 코드에 5월만 있다.)

캘린더에 잘 추가된 모습.

📅 구글 캘린더 일정 삭제

    def get_total_google_calendar(self):
        creds = self.renew_google_token()
        service = build('calendar', 'v3', credentials=creds)
        page_token = None
        event_list = []

        while True:
            events = service.events().list(calendarId=config.calendar_id, pageToken=page_token).execute()
            for event in events['items']:
                event_list.append(event)
            page_token = events.get('nextPageToken')
            if not page_token:
                break

        return event_list

    def delete_google_calendar(self, event_id):
        creds = self.renew_google_token()
        service = build('calendar', 'v3', credentials=creds)

        service.events().delete(calendarId=config.calendar_id, eventId=event_id).execute()

이전에 만들어두었던 클래스에 두 가지를 추가하였다.
전체일정을 가져오는 함수와 일정의 id값으로 삭제 하는 함수를 추가해준다.

def delete_game_schedule():
    google_calendar = GoogleCalendar()

    game_list = google_calendar.get_total_google_calendar()
    for game in game_list:
        if game.get("description") and game["description"] == "야구 경기":
            google_calendar.delete_google_calendar(game["id"])

그리고 description이 야구 경기로 되어있는 경우에 전체 삭제를 진행해준다.

전체코드

0개의 댓글