1. API 발급 Site
- http://www.kobis.or.kr/kobisopenapi/homepg/main/main.do
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. 시각화 결과값
'Python_Intermediate > API' 카테고리의 다른 글
[API]Python Study - PPT Presentation Material (0) | 2019.12.22 |
---|---|
[API]KAKAO API 발급 방법(카카오 API) (0) | 2019.12.15 |
API - Naver searching call example (0) | 2019.08.21 |