YOGYUI

공공데이터포털::공휴일 데이터 조회 (REST API) 본문

Data Analysis/Data Engineering

공공데이터포털::공휴일 데이터 조회 (REST API)

요겨 2021. 4. 3. 22:28
반응형

회사에서 사원별 공수(Man Hour) 관리 프로그램을 하나 만들었는데, 공휴일에는 입력이 안되게 만드는 기능이 필요하게 됐다

 

파이썬 써드파티 라이브러리 종류도 몇 개 있어 찾아봤는데, 중국의 국경일을 기반으로 한국의 실정에 맞게 변환해야 하는 경우가 대부분이라 번거로울 뿐만 아니라 대통령 선거같은 이벤트나 임시공휴일은 유저가 따로 입력해야 하는 불편함이 있다

 

확실한 건 웹크롤링인데, (ex: 주식시장 개장일) 공공데이터포털에서도 API 몇 개가 공개되어 있어서 그 중 한개를 사용하도록 했다

 

1. 공공데이터포털 API 활용신청

데이터 타이틀은 "특일 정보", URL은 아래 링크 참고

https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15012690

 

메타데이터 정보

한국천문연구원(?!)에서 제공하는 데이터로, 국경일 및 공휴일 뿐만 아니라 24절기 등 유용한 정보를 긁어올 수 있다

 

바로 API 활용신청 (신청법은 링크 참고)하고 인증키를 받아오자

개발계정 상세보기 - 인증키 확인

(인증안된다는 문의가 너무 많아서 그런가, URL 인코딩된 인증키랑 일반 인증키 둘 다 기재해뒀다 ㅋㅋ)

 

서비스 URL: http://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/{서비스오퍼레이션}

필요한 정보에 따라 URL 뒤에 붙여야하는 문자열(서비스오퍼레이션)이 다르다

서비스 종류 서비스 오퍼레이션명
국경일 정보조회 getHoliDeInfo
공휴일 정보조회 getRestDeInfo
기념일 정보조회 getAnniversaryInfo
24절기 정보조회 get24DivisionsInfo
잡절 정보조회 getSundryDayInfo

호출 파라미터는 다음과 같다

필요한 정보는 모두 얻었으니 바로 코딩해보자

2. 테스트 코드

import requests
from urllib import parse

url = "http://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/"
api_key_utf8 = "Your API Key from data.go.kr"
api_key_decode = parse.unquote(api_key_utf8)

url_holiday = url + "getRestDeInfo"
params = {
    "ServiceKey": api_key_decode,
    "solYear": 2021,
    "numOfRows": 100
}

response = requests.get(url_holiday, params=params)

2021년 전체의 공휴일(getRestDeInfo)을 요청해봤다

공휴일이 100일을 넘는 경우는 없을테니 대충 한 페이지에 표시할 아이템 수(numOfRows)는 100으로 설정

In [1]: print(response.text)
Out[1]:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
  <header>
    <resultCode>00</resultCode>
    <resultMsg>NORMAL SERVICE.</resultMsg>
  </header>
  <body>
    <items>
      <item>
        <dateKind>01</dateKind>
        <dateName>1월1일</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210101</locdate>
        <seq>1</seq>
      </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>설날</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210211</locdate>
        <seq>1</seq>
      </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>설날</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210212</locdate>
        <seq>1</seq>
        </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>설날</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210213</locdate>
        <seq>1</seq>
      </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>삼일절</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210301</locdate>
        <seq>1</seq>
      </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>어린이날</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210505</locdate>
        <seq>1</seq>
      </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>부처님오신날</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210519</locdate>
        <seq>1</seq>
      </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>현충일</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210606</locdate>
        <seq>1</seq>
      </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>광복절</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210815</locdate>
        <seq>1</seq>
      </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>추석</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210920</locdate>
        <seq>1</seq>
      </item>
	  <item>
        <dateKind>01</dateKind>
        <dateName>추석</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210921</locdate>
        <seq>1</seq>
	  </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>추석</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20210922</locdate>
        <seq>1</seq>
	  </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>개천절</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20211003</locdate>
        <seq>1</seq>
      </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>한글날</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20211009</locdate>
        <seq>1</seq>
      </item>
      <item>
        <dateKind>01</dateKind>
        <dateName>기독탄신일</dateName>
        <isHoliday>Y</isHoliday>
        <locdate>20211225</locdate>
        <seq>1</seq>
      </item>  
    </items>
    <numOfRows>100</numOfRows>
    <pageNo>1</pageNo>
    <totalCount>15</totalCount>
  </body>
</response>

 

총 아이템 수는 15개이고, 3일씩 연속되는 설날과 추석을 고려하면 11개의 공휴일이 있는 것으로 나온다

웹에서 검색한 다른 데이터와도 일치한다

출처: https://publicholidays.co.kr/ko/2021-dates/

아이템의 태그들에 대한 설명은 다음과 같다

dateKind 종류
01: 국경일 (ex: 어린이날, 광복절, 개천절)
02: 기념일 (ex: 의병의 날, 정보보호의 날, 4/19 혁명 기념일)
03: 24절기 (ex: 청명, 경칩, 하지)
04: 잡절 (ex: 단오, 한식)
dateName 명칭
isHoliday 공공기관 휴일여부
locdate 날짜
seq 순번

12월 25일을 크리스마스나 성탄절이 아니라 '기독탄신일'이라고 부르는게 인상적이다

(석가탄신일은 또 부처님오신날이라고 하네? ㅋㅋ)

3. Pandas DataFrame

공휴일을 크롤링하는 구문을 함수화해보자 (반환은 pandas DataFrame으로)

import requests
from urllib import parse
import pandas as pd
from bs4 import BeautifulSoup
from datetime import datetime

def getHoliday(year: int) -> pd.DataFrame:
    url = "http://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo"
    api_key_utf8 = "Your API Key from data.go.kr"
    api_key_decode = parse.unquote(api_key_utf8)

    params = {
        "ServiceKey": api_key_decode,
        "solYear": year,
        "numOfRows": 100
    }

    response = requests.get(url, params=params)
    xml = BeautifulSoup(response.text, "lxml")
    items = xml.find('items')
    item_list = []
    for item in items:
        item_dict = {
            "이름": item.find("datename").text.strip(),
            "날짜": datetime.strptime(item.find("locdate").text.strip(), '%Y%m%d')
        }
        item_list.append(item_dict)

    return pd.DataFrame(item_list)
In [2]: print(getHoliday(2021))
Out[2]:
        이름        날짜
0   1월1일        2021-01-01
1   설날          2021-02-11
2   설날          2021-02-12
3   설날          2021-02-13
4   삼일절        2021-03-01
5   어린이날      2021-05-05
6   부처님오신날  2021-05-19
7   현충일        2021-06-06
8   광복절        2021-08-15
9   추석          2021-09-20
10  추석          2021-09-21
11  추석          2021-09-22
12  개천절        2021-10-03
13  한글날        2021-10-09
14  기독탄신일    2021-12-25

테스트삼아 2022년 공휴일도 한번 불러와봤다

In [3]: print(getHoliday(2022))
Out[3]:
          이름           날짜
0   1월1일            2022-01-01
1   설날              2022-01-31
2   설날              2022-02-01
3   설날              2022-02-02
4   삼일절            2022-03-01
5   대통령선거일      2022-03-09
6   어린이날          2022-05-05
7   부처님오신날      2022-05-08
8   전국동시지방선거  2022-06-01
9   현충일            2022-06-06
10  광복절            2022-08-15
11  추석              2022-09-09
12  추석              2022-09-10
13  추석              2022-09-11
14  대체공휴일        2022-09-12
15  개천절            2022-10-03
16  한글날            2022-10-09
17  기독탄신일        2022-12-25

선거일까지 잘 반영이 된다!

 

데이터프레임에 요일 정보까지 함께 포함하고 싶으면 다음과 같이 추가해주면 된다
(datetime weekday() 사용)

def getHoliday(year: int) -> pd.DataFrame:
    url = "http://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo"
    api_key_utf8 = "Your API Key from data.go.kr"
    api_key_decode = parse.unquote(api_key_utf8)

    params = {
        "ServiceKey": api_key_decode,
        "solYear": year,
        "numOfRows": 100
    }

    temp = ["월", "화", "수", "목", "금", "토", "일"]

    response = requests.get(url, params=params)
    xml = BeautifulSoup(response.text, "lxml")
    items = xml.find('items')
    item_list = []
    for item in items:
        dt = datetime.strptime(item.find("locdate").text.strip(), '%Y%m%d')
        item_dict = {
            "이름": item.find("datename").text.strip(),
            "날짜": dt,
            "요일": temp[dt.weekday()]
        }
        item_list.append(item_dict)

    return pd.DataFrame(item_list)
In [4]: print(getHoliday(2021))
Out[4]:
        이름        날짜       요일
0   1월1일        2021-01-01   금
1   설날          2021-02-11   목
2   설날          2021-02-12   금
3   설날          2021-02-13   토
4   삼일절        2021-03-01   월
5   어린이날      2021-05-05   수
6   부처님오신날  2021-05-19   수
7   현충일        2021-06-06   일
8   광복절        2021-08-15   일
9   추석          2021-09-20   월
10  추석          2021-09-21   화
11  추석          2021-09-22   수
12  개천절        2021-10-03   일
13  한글날        2021-10-09   토
14  기독탄신일    2021-12-25   토

두고두고 유용하게 잘 써먹을 수 있을 것 같다

끝~!

 

 

반응형