오늘은 상장된 단일기업의 재무제표를 가져오는 크롤링을 해보도록 하겠습니다.
일단, 다트의 공시 API를 가져오기 위해서 Open DART 사이트에 들어갑니다.
1) 회원가입 후, 인증키를 신청합니다
2) "인증키 신청/관리 > 인증키 관리" 를 통해 승인이 되어 있는지 확인합니다
3) "인증키 신청/관리 > 오픈 API 이용현황"에서 API key를 가지고 옵니다
API key를 가지고 왔다면 크롤링 준비를 다 마쳤습니다.
(1) 상장기업의 고유번호 크롤링
(* 금융업을 제외한 유가증권 및 코스닥 상장회사 )
일단, 재무제표를 크롤링 하기 앞서 각 상장기업의 고유번호를 먼저 크롤링 해와야 합니다.
인증키를 지정하고, 라이브러리를 import 해 줍니다.
crtfc_key = '본인의 인증키 번호'
import requests
import pandas as pd
import io
import zipfile
import xml.etree.ElementTree as et
import json
이제 고유번호를 가져오면 됩니다.
고유번호 크롤링 방법은 "오픈DART > 개발가이드 > 공시정보 목록> 고유번호"를 보면 확인하실 수 있습니다.
1) 기본 정보를 통해 요청 url을 확인합니다.
- 출력 포맷이 ZIP file이고, 인코딩이 utf-8이라는 것을 확인할 수 있습니다.
- 그러므로 zipfile로 불러오고 zipfile을 열어주는 작업이 필요합니다.
- 또한, utf-8로 인코딩 되어있는 file을 디코딩 해주는 작업도 필요합니다.
2) 요청인자가 무엇인지 확인합니다.
- 이 경우, API 인증키만 확인하면 됩니다.
3) 응답결과 출력값이 무엇인지 확인합니다
- status, message는 오류가 떴을 경우 확인을 위함입니다.
- 상정기업 고유번호를 제대로 크롤링해오면, 그 기업의 고유번호와, 정식명칭, 종목코드, 최종변경일자가 출력값으로 나오게 됩니다.
이제, 고유번호를 크롤링해오는 함수를 만들어봅시다.
함수 설명
1) 요청 url에 필요한 요청 인자를 지정해줍니다. (dict 형식, params )
2) 출력값과 출력값의 이름을 지정해줍니다(items, item_names)
3) 요청 url을 넣고, request 해줍니다.
4) zipfile로 이를 받고, 열어서 디코딩 해줍니다.
5) 종목코드가 있는 경우만 받아서 이를 데이터프레임으로 만들어주면 함수가 완성됩니다.
def get_corpcode(crtfc_key):
"""
OpenDART 기업 고유번호 받아오기
return 값: 주식코드를 가진 업체의 DataFrame
"""
params = {'crtfc_key':crtfc_key}
items = ["corp_code","corp_name","stock_code","modify_date"]
item_names = ["고유번호","회사명","종목코드","수정일"]
url = "https://opendart.fss.or.kr/api/corpCode.xml" #요청 url
res = requests.get(url,params=params) #url 불러오기
zfile = zipfile.ZipFile(io.BytesIO(res.content)) #zip file 받기
fin = zfile.open(zfile.namelist()[0]) #zip file 열고
root = et.fromstring(fin.read().decode('utf-8')) #utf-8 디코딩
data = []
for child in root:
if len(child.find('stock_code').text.strip()) > 1: # 종목코드가 있는 경우
data.append([]) #data에 append하라
for item in items:
data[-1].append(child.find(item).text)
df = pd.DataFrame(data, columns=item_names)
return df
이제 함수를 적용해봅시다.
stock_comp = get_corpcode(crtfc_key)
stock_comp
(2) 단일회사 상장기업 재무제표 크롤링
1) url request 및 데이터프레임으로 변환하는 함수
재무제표 크롤링에 앞서 json 형식으로 url을 request하고, 이를 dataframe으로 형식으로 바꾸는 함수를 먼저 만들어보겠습니다.
1) url과 요청인자 params를 만들고 이를 request 해줍니다.
2) data를 받았다면 이를 append 해주고 dataframe 형식으로 바꾸어줍니다.
def Frame(url, items, item_names, params):
"""
url : json형태로 요청하는 주소
items : 반환되는 데이터들의 key를 가진 리스트
item_names : 데이터프레임을 만들때 컬럼명 리스트
params : url 요청시 필수값으로 들어가는 인자들을 가진 딕셔너리
"""
res = requests.get(url, params)
json_data = res.json()
json_dict = json.loads(res.text)
data = []
if json_dict['status'] == "000": # 오류 없이 정상적으로 데이터가 있다면
for line in json_dict['list']:
data.append([])
for itm in items:
if itm in line.keys():
data[-1].append(line[itm])
else:
data[-1].append('')
df = pd.DataFrame(data, columns=item_names)
return df
2) 단일회사 재무제표 크롤링
1) 기본 정보를 통해 요청 url을 확인합니다.
- 요청할수 있는 형식은 json, xml 두가지 입니다.
- json 형식을 사용하도록 하겠습니다.
2) 요청인자가 무엇인지 확인합니다.
- API key와 크롤링해온 기업의 고유 번호가 필요합니다.
- 사업 연도 (2015년 이후) 도 필요합니다.
- 어떤 보고서를 가져올지 선택해야합니다. (1분기 : 11013, 반기 : 11012, 3분기 :11014, 사업보고서 : 11011)
- 또한, 재무제표가 개별재무제표(OFS)인지 연결재무제표(CFS)인지 확인해야합니다.
- 저는 모든 상장기업의 2020년 1분기의 연결재무제표를 가지고 와보도록 하겠습니다.
Q. 연결재무제표란? A. 상장기업과 연결되어 있는 모든 기업을 다 포함한 재무제표
3) 응답결과 출력값이 무엇인지 확인합니다
- 이는 "개발가이드 > 상장기업재무정보 > 단일회사 전체 재무제표"를 들어가면 확인 가능합니다
- 링크: opendart.fss.or.kr/guide/detail.do?apiGrpCd=DS003&apiId=2019020
함수 설명
1) 출력값(items)와 출력값의 컬럼명(item_names)를 설정해 준 후, url을 request 하고 이를 Frame 함수에 적용합니다.
2) Frame 함수는 json 형식의 url을 요청해 데이터를 가져오고, 이를 dataframe으로 바꾸어 줍니다.
def get_단일회사재무제표(crtfc_key, corp_code, bsns_year, reprt_code, fs_div = "CFS"):
items = ["rcept_no","reprt_code","bsns_year","corp_code","sj_div","sj_nm",
"account_id","account_nm","account_detail","thstrm_nm", "thstrm_amount",
"thstrm_add_amount","frmtrm_nm","frmtrm_amount", "frmtrm_q_nm","frmtrm_q_amount",
"frmtrm_add_amount","bfefrmtrm_nm", "bfefrmtrm_amount","ord"]
item_names = ["접수번호","보고서코드","사업연도","고유번호","재무제표구분", "재무제표명",
"계정ID","계정명","계정상세","당기명","당기금액", "당기누적금액","전기명","전기금액","전기명(분/반기)",
"전기금액(분/반기)","전기누적금액","전전기명","전전기금액", "계정과목정렬순서"]
params = {'crtfc_key':crtfc_key, 'corp_code':corp_code, 'bsns_year':bsns_year, 'reprt_code':reprt_code, 'fs_div':fs_div}
url = "https://opendart.fss.or.kr/api/fnlttSinglAcntAll.json?"
df = Frame(url, items, item_names, params)
return df
이제 이를 함수에 적용해봅시다.
#1개 해보기
corp_code = stock_comp['고유번호']
final_reprt_df = get_fnlttSinglAcntAll(crtfc_key, corp_code[0], 2020, '11013', fs_div = "CFS")
#반복
from tqdm import tqdm
for k in tqdm(range(1, len(stock_comp))):
reprt_df = get_fnlttSinglAcntAll(crtfc_key, corp_code[k], 2020, '11013', fs_div = "CFS")
final_reprt_df = pd.concat([final_reprt_df, reprt_df], axis = 0)
총 3241개 상장기업의 2020년 1분기 연결재무제표를 크롤링해보았습니다.
이제 이를 각각 재무재표의 형식에 따라 나누어줍니다.
def sep(x, df):
df = df[df['재무제표구분'] == x]
return df
final_BS = sep('BS', final_reprt_df) #재무상태표
final_CIS = sep('CIS', final_reprt_df) #포괄손익계산서
final_CF = sep('CF', final_reprt_df) #현금흐름표
final_SCE = sep('SCE', final_reprt_df) #자본변동표
final_IS = sep('IS', final_reprt_df) #손익계산서
*전처리 과정은 다음에 올리도록 하겠습니다.
아래 링크를 참고하여 크롤링 해보았습니다.
https://besixdouze.net/18?category=909673
'etc > Crawling' 카테고리의 다른 글
[R] OpenDART 크롤링 (2) - 단일기업 전체 재무제표 가져오는 함수 (1) | 2020.12.02 |
---|---|
[R] OpenDART API 크롤링 (1) - 상장기업 고유번호 가져오기 (0) | 2020.12.02 |