본문 바로가기

Python_Intermediate/API

[API]영화진흥원 박스오피스 순위 분위

 

 

1. API 발급 Site

- http://www.kobis.or.kr/kobisopenapi/homepg/main/main.do

 

영화진흥위원회 오픈API

 

www.kobis.or.kr

 

2. 데이터 작업 절차

- 수집(Data Collection) > 전처리(Data pretreatment) > 정제(Data refining) > 시각화(Data Visualization)

 

3. 사용 패키지

import datetime as dt
import requests
import json
import pandas as pd
from pandas import DataFrame
from matplotlib import pyplot as plt
from print_df import print_df

 

4. 데이터 수집

# 영화 진흥원에서 발급받은 API키
# kobis.or.kr
kobis_api_key = ''

# 요청에 필요한 파라미터(API)
# key -> 문자열(필수) / 발급받은 키 값을 입력
# targetDt -> 문자열(필수) / 조회하고자 하는 날짜를 yyyymmdd 형식으로 입력

# 형식은 JSON

# 영화진흥원 API URL
kobis_api_url = 'http://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=%s&targetDt=%s'

# 날짜 동적 생성(현재날짜 - 1일)
# 파라미터로 전달하기 위한 하루 전 날짜값 만들기
today = dt.datetime.now()                       # 오늘날짜
delta = dt.timedelta(days=-1)                   # 하루 전을 의미하는 timedelta객체
yesterday = today + delta                       # 오늘 날짜와 timedelta 연산
yesterday_str = yesterday.strftime('%Y%m%d')    # yyyymmdd 형식 문자열로 변환

# API키와 날짜를 조합하여 접속할 URL 구성
# http://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=발급받은키&targetDt=하루전날짜
api_url = kobis_api_url % (kobis_api_key, yesterday_str)
print(api_url)

> 결과값

http://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=발급API키값&targetDt=20200210

# URL에 접속해서 결과를 가져옴
r = requests.get(api_url)

# 접속에 실패한 경우(status_code가 200이 아닌경우는 모두 에러 간주)
if r.status_code != 200:
    # 에러코드와 에러메시지 출력
    print('[%d Error] %s' % (r.status_code, r.reason))
    # 프로그램 강제 종료
    quit()

# 가져온 결과를 딕셔너리로 변환
r.encoding = 'utf-8'
result = json.loads(r.text)
print(result)

> 결과값

{'boxOfficeResult': {'boxofficeType': '일별 박스오피스', 'showRange': '20200210~20200210', 'dailyBoxOfficeList': [{'rnum': '1', 'rank': '1', 'rankInten': '0', 'rankOldAndNew': 'OLD', 'movieCd': '20182447', 'movieNm': '클로젯', 'openDt': '2020-02-05', 'salesAmt': '654353440', 'salesShare': 
'47.9', 'salesInten': '-1042920150', 'salesChange': '-61.4', 'salesAcc': '6620957280', 'audiCnt': '78754', 'audiInten': '-109471', 'audiChange': 
'-58.2', 'audiAcc': '759934', 'scrnCnt': '1094', 'showCnt': '5606'}, {'rnum': '2', 'rank': '2', 'rankInten': '1', 'rankOldAndNew': 'OLD', 'movieCd': '20198431', 'movieNm': '버즈 오브 프레이(할리 퀸의 황홀한 해방)', 'openDt': '2020-02-05', 'salesAmt': '221207150', 'salesShare': '16.2', 'salesInten': '-325527850', 'salesChange': '-59.5', 'salesAcc': '2561728930', 'audiCnt': '26205', 'audiInten': '-32899', 'audiChange': '-55.7', 'audiAcc': '286604', 'scrnCnt': '831', 'showCnt': '3623'}, {'rnum': '3', 'rank': '3', 'rankInten': '-1', 'rankOldAndNew': 'OLD', 'movieCd': '20180939', 'movieNm': '남산의 부장들', 'openDt': '2020-01-22', 'salesAmt': '204146020', 'salesShare': '14.9', 'salesInten': '-333457380', 'salesChange': '-62', 'salesAcc': '40001673250', 'audiCnt': '25132', 'audiInten': '-34763', 'audiChange': '-58', 'audiAcc': '4605239', 'scrnCnt': '767', 'showCnt': '2902'}, {'rnum': '4', 'rank': '4', 'rankInten': '0', 'rankOldAndNew': 'OLD', 'movieCd': '20192101', 'movieNm': '히트맨', 'openDt': '2020-01-22', 'salesAmt': '115264090', 'salesShare': '8.4', 'salesInten': '-204916910', 'salesChange': '-64', 'salesAcc': '20266906460', 'audiCnt': '14279', 'audiInten': '-23653', 'audiChange': '-62.4', 'audiAcc': '2362487', 'scrnCnt': '621', 'showCnt': '2023'}, {'rnum': '5', 'rank': '5', 'rankInten': '1', 'rankOldAndNew': 'OLD', 'movieCd': '20197390', 'movieNm': '조조 래빗', 'openDt': '2020-02-05', 'salesAmt': '46115460', 'salesShare': '3.4', 'salesInten': '-43147820', 'salesChange': '-48.3', 'salesAcc': '361421000', 'audiCnt': '5600', 'audiInten': '-4380', 'audiChange': '-43.9', 'audiAcc': '42245', 'scrnCnt': '254', 'showCnt': '527'}, {'rnum': '6', 'rank': '6', 'rankInten': '1', 'rankOldAndNew': 'OLD', 'movieCd': '20100312', 'movieNm': '인셉션', 'openDt': '2010-07-21', 'salesAmt': '19740000', 'salesShare': '1.4', 'salesInten': '-21819000', 'salesChange': '-52.5', 'salesAcc': '44282775800', 'audiCnt': '2410', 'audiInten': '-2212', 'audiChange': '-47.9', 'audiAcc': '5931255', 'scrnCnt': '145', 'showCnt': '302'}, {'rnum': '7', 'rank': '7', 'rankInten': '2', 'rankOldAndNew': 'OLD', 'movieCd': '20191109', 'movieNm': '페인 앤 글로리', 'openDt': '2020-02-05', 'salesAmt': '15679320', 'salesShare': '1.1', 'salesInten': '-6212760', 'salesChange': '-28.4', 'salesAcc': '161796100', 'audiCnt': '2354', 'audiInten': '-165', 'audiChange': '-6.6', 'audiAcc': '21150', 'scrnCnt': '165', 'showCnt': '274'}, {'rnum': '8', 'rank': '8', 'rankInten': '-3', 'rankOldAndNew': 'OLD', 'movieCd': '20192984', 'movieNm': '극장판 미니특공대: 공룡왕 디노 ', 'openDt': '2020-02-06', 'salesAmt': '16658760', 'salesShare': '1.2', 'salesInten': '-106615680', 'salesChange': '-86.5', 'salesAcc': '348008060', 'audiCnt': '2268', 'audiInten': '-13352', 'audiChange': '-85.5', 'audiAcc': '44423', 'scrnCnt': '343', 'showCnt': '430'}, {'rnum': '9', 'rank': '9', 'rankInten': '29', 'rankOldAndNew': 'OLD', 'movieCd': '20183782', 'movieNm': '기생충', 'openDt': '2019-05-30', 'salesAmt': '11920500', 'salesShare': '0.9', 'salesInten': '11329500', 'salesChange': '1917', 'salesAcc': '86000559825', 'audiCnt': '1761', 'audiInten': '1693', 'audiChange': '2489.7', 'audiAcc': '10100373', 'scrnCnt': '73', 'showCnt': '103'}, {'rnum': '10', 'rank': '10', 'rankInten': '0', 'rankOldAndNew': 'OLD', 'movieCd': '20198676', 'movieNm': '타오르는 여인의 초상', 
'openDt': '2020-01-16', 'salesAmt': '11565440', 'salesShare': '0.8', 'salesInten': '-11098800', 'salesChange': '-49', 'salesAcc': '1072920008', 'audiCnt': '1435', 'audiInten': '-994', 'audiChange': '-40.9', 'audiAcc': '128279', 'scrnCnt': '111', 'showCnt': '148'}]}}

 

5. 데이터 전처리

# 결과에서 영화 목록 배열을 데이터프레임으로 변환
df = DataFrame(result['boxOfficeResult']['dailyBoxOfficeList'])
print_df(df.head())

> 결과값

+---+------+------+-----------+---------------+----------+-----------------------------------------+------------+-----------+------------+-------------+-------------+-------------+---------+-----------+------------+---------+---------+---------+
|   | rnum | rank | rankInten | rankOldAndNew | movieCd  |                 movieNm                 |   openDt   |  salesAmt | salesShare |  salesInten | salesChange |   salesAcc  | audiCnt | audiInten | audiChange | audiAcc | scrnCnt | showCnt |
+---+------+------+-----------+---------------+----------+-----------------------------------------+------------+-----------+------------+-------------+-------------+-------------+---------+-----------+------------+---------+---------+---------+
| 0 |  1   |  1   |     0     |      OLD      | 20182447 |                  클로젯                 | 2020-02-05 | 654353440 |    47.9    | -1042920150 |    -61.4    |  6620957280 |  78754  |  -109471  |   -58.2    |  759934 |   1094  |   5606  |
| 1 |  2   |  2   |     1     |      OLD      | 20198431 | 버즈 오브 프레이(할리 퀸의 황홀한 해방) | 2020-02-05 | 221207150 |    16.2    |  -325527850 |    -59.5    |  2561728930 |  26205  |   -32899  |   -55.7    |  286604 |   831   |   3623  |
| 2 |  3   |  3   |     -1    |      OLD      | 20180939 |              남산의 부장들              | 2020-01-22 | 204146020 |    14.9    |  -333457380 |     -62     | 40001673250 |  25132  |   -34763  |    -58     | 4605239 |   767   |   2902  |
| 3 |  4   |  4   |     0     |      OLD      | 20192101 |                  히트맨                 | 2020-01-22 | 115264090 |    8.4     |  -204916910 |     -64     | 20266906460 |  14279  |   -23653  |   -62.4    | 2362487 |   621   |   2023  |
| 4 |  5   |  5   |     1     |      OLD      | 20197390 |                조조 래빗                | 2020-02-05 |  46115460 |    3.4     |  -43147820  |    -48.3    |  361421000  |   5600  |   -4380   |   -43.9    |  42245  |   254   |   527   |
+---+------+------+-----------+---------------+----------+-----------------------------------------+------------+-----------+------------+-------------+-------------+-------------+---------+-----------+------------+---------+---------+---------+

# 분석에 필요한 컬럼 추출하기
# 영화제목과 관람객수만 필터링 -> 막대그래프 생성
df = df.filter(items=['movieNm', 'audiCnt'])
print_df(df.head())

> 결과값

+---+-----------------------------------------+---------+
|   |                 movieNm                 | audiCnt |
+---+-----------------------------------------+---------+
| 0 |                  클로젯                 |  78754  |
| 1 | 버즈 오브 프레이(할리 퀸의 황홀한 해방) |  26205  |
| 2 |              남산의 부장들              |  25132  |
| 3 |                  히트맨                 |  14279  |
| 4 |                조조 래빗                |   5600  |
+---+-----------------------------------------+---------+

# 영화제목 -> 데이터프레임 인덱스
# 영화이름을 딕셔너리의 리스트로 사용하기
movie_list = list(df['movieNm'])    # -> 영화이름만 리스트로 추출
index_dict = {}                     # -> 인덱스 이름 변경사항을 설정할 딕셔너리

for i, v in enumerate(movie_list):  # -> {현재인덱스: 신규인덱스} 형식으로 재구성
    index_dict[i] = v

# 딕셔너리의 인덱스와 컬럼이름을 변경
df.rename(index=index_dict, columns={'audiCnt': '관람객수'}, inplace=True)

# 영화제목에 대한 열은 삭제
df.drop('movieNm', axis=1, inplace=True)

# 변환결과 확인
print_df(df.head())

> 결과값

+-----------------------------------------+----------+
|                                         | 관람객수 |
+-----------------------------------------+----------+
|                  클로젯                 |  78754   |
| 버즈 오브 프레이(할리 퀸의 황홀한 해방) |  26205   |
|              남산의 부장들              |  25132   |
|                  히트맨                 |  14279   |
|                조조 래빗                |   5600   |
+-----------------------------------------+----------+

# 통계를 수행할 컬럼의 데이터 확인
# 관람객수 열 확인
print_df(df['관람객수'])

> 결과값

클로젯                        78754
버즈 오브 프레이(할리 퀸의 황홀한 해방)    26205
남산의 부장들                    25132
히트맨                        14279
조조 래빗                       5600
인셉션                         2410
페인 앤 글로리                    2354
극장판 미니특공대: 공룡왕 디노           2268
기생충                         1761
타오르는 여인의 초상                 1435
Name: 관람객수, dtype: object

# pandas.to_numeric : 숫자 형식으로 형변환
# 관람객수 열의 타입을 숫자 형식으로 변환
df['관람객수'] = df['관람객수'].apply(pd.to_numeric)

# dtype : int64 -> int 형식으로 형 변환 확인
# 관람객수 열 재확인
print_df(df['관람객수'])

> 결과값

클로젯                        78754
버즈 오브 프레이(할리 퀸의 황홀한 해방)    26205
남산의 부장들                    25132
히트맨                        14279
조조 래빗                       5600
인셉션                         2410
페인 앤 글로리                    2354
극장판 미니특공대: 공룡왕 디노           2268
기생충                         1761
타오르는 여인의 초상                 1435
Name: 관람객수, dtype: int64

# 특정 열로 내림차순 정렬
# ascending=False 내림차순
# ascending=True 오름차순 (기본값)
df.sort_values('관람객수', inplace=True, ascending=True)
print_df(df)

> 결과값

+-----------------------------------------+----------+
|                                         | 관람객수 |
+-----------------------------------------+----------+
|           타오르는 여인의 초상          |   1435   |
|                  기생충                 |   1761   |
|     극장판 미니특공대: 공룡왕 디노      |   2268   |
|              페인 앤 글로리             |   2354   |
|                  인셉션                 |   2410   |
|                조조 래빗                |   5600   |
|                  히트맨                 |  14279   |
|              남산의 부장들              |  25132   |
| 버즈 오브 프레이(할리 퀸의 황홀한 해방) |  26205   |
|                  클로젯                 |  78754   |
+-----------------------------------------+----------+

 

6. 데이터 정제

# 관람객 수가 집계 되어 있지 않은 경우도 있기때문에 결측치 제거
# 결측치가 있는 모든 행 삭제
df = df.dropna()
empty_sum = df.isnull().sum()
print_df(empty_sum)

> 결과값

관람객수    0
dtype: int64

 

7. 데이터 시각화

# 그래프 만들기
plt.rcParams['font.family'] = 'NanumGothic'          # 한글 폰트 지정(나눔고딕)
plt.rcParams['font.size'] = 14                       # 그래프 폰트 사이즈(14)
plt.rcParams['figure.figsize'] = (16, 8)             # 그래프 사이즈(16 x 8)

# 전체 컬럼에 대한 시각화
df.plot.barh()                                       # 막대그래프
plt.grid()                                           # 격자무늬
plt.title('%s 박스오피스 순위' % yesterday_str)      # 그래프 제목
plt.legend()                                         # 범주
plt.savefig('boxoffice_daily.png', dpi=200)          # 그래프 저장(dpi -> 해상도)
plt.show()                                           # 그래프 보기
plt.close()                                          # 그래프 종료

 

8. 시각화 결과값