DART API를 이용하여 받은 재무제표 데이터를 엑셀로 정리하는 코딩을 하였다. 파이썬 - xlwings 모듈을 활용하였다.
반대로 재무제표를 불러올 종목코드는 엑셀에서 불러오도록 하였다.
이전 프로그램에서 추가로 영업활동으로 인한 현금흐름과 주당이익을 추가하기 위하여, 전체 재무제표 정보를 활용하였다.
opendart.fss.or.kr/guide/detail.do?apiGrpCd=DS003&apiId=2019020
전자공시 OPENDART 시스템 | 개발가이드 | 상세
상장기업 재무정보 개발가이드 상장기업 재무정보 단일회사 전체 재무제표 단일회사 전체 재무제표 개발가이드 기본 정보 기본 정보 메서드 요청URL 인코딩 출력포멧 GET https://opendart.fss.or.kr/api/
opendart.fss.or.kr
1. 전체 재무제표는 개별/연결 구분 정보를 추가로 요구한다. 연결재무제표(CFS)를 우선으로 확인하고, 없는 경우엔 재무제표(OFS) 를 확인하도록 하였다.
2. 힘들었던 부분은 재무제표마다 재무 항목을 나타내는 양식이 일치하지 않았다. 예를들어 매출액을 나타내는 단어는
'수익(매출액)', '영업수익', '매출액 및 지분법손익', '매출', 'I. 매출액','I.매출액','I.매출', '수익', '영업수익(매출액)' 등이 있었다. 각 재무 항목을 표현하는 단어들의 리스트를 작성하여, 이 리스트 항목이 재무제표에 있는 경우 값을 읽오도록 하였다.
3. 주당이익엔 계속주당이익과 중단주당이익이 있다. 주당이익은 두 가지 항목의 합으로 반영될 수 있도록 하였다.
전체코드
import xlwings as xw
from bs4 import BeautifulSoup
from urllib.request import urlopen
import pandas as pd
import xml.etree.ElementTree as elemTree
import time
#기업 코드 불러오기
tree = elemTree.parse("corp_num\CORPCODE.xml")
datalist = tree.findall("list")
corp_code = [x.findtext("corp_code") for x in datalist]
corp_name = [x.findtext("corp_name") for x in datalist]
stock_code = [x.findtext("stock_code") for x in datalist]
stocklist={}
for i in range(len(corp_code)):
stocklist[stock_code[i]]=[corp_name[i], corp_code[i]]
#API 키
auth_key = '##########################'
#데이터 불러오기 함수
def get_Data(stock_code, start_year):
stock_code_find = str(stock_code)
#종목 코드를 이용하여 기업 코드 찾기
corp_code_find = stocklist[stock_code_find][1]
#보고서를 읽어오고자 하는 해당 년도
start_year=str(start_year)
report_list = ['11011','11014','11012','11013']
# 1분기 보고서 : 11013
# 반기 보고서 : 11012
# 3분기 보고서 : 11014
# 사업 보고서 : 11011
# 분기 별로 1분기, 반기, 3분기, 사업 보고서를 차례로 불러옴
for report_temp in report_list:
report_code = report_temp
#공시 시기 리스트 작성
report_type = {'11013':'03','11012':'06','11014':'09','11011':'12'}
report_date = start_year+"_"+report_type[report_code]
#xml 형식으로 데이터 요청
url = 'https://opendart.fss.or.kr/api/fnlttSinglAcntAll.xml?crtfc_key=' + auth_key + '&corp_code=' + corp_code_find + '&bsns_year=' + start_year + '&reprt_code=' + report_code + '&fs_div=CFS'
data = urlopen(url)
data_xml = BeautifulSoup(data.read(),'html.parser')
#재무제표 정보가 포함된 list 항목만 추출
data_list = data_xml.find_all("list")
#연결재무제표가 없는 경우
if len(data_list) == 0:
url = 'https://opendart.fss.or.kr/api/fnlttSinglAcntAll.xml?crtfc_key=' + auth_key + '&corp_code=' + corp_code_find + '&bsns_year=' + start_year + '&reprt_code=' + report_code + '&fs_div=OFS'
data = urlopen(url)
data_xml = BeautifulSoup(data.read(), 'html.parser')
data_list = data_xml.find_all("list")
#print(data_list)
value =[]
index =[]
data_dic={}
#thstrm_amount : 당기의 재무 정보
#sj_nm : 연결 재무제표 여부
#account_nm : 재무제표 항목
#연결 재무 여부와 항목을 합쳐서 index로 사용
for i in data_list:
if i.sj_nm.string != "자본변동표":
value.append(i.thstrm_amount.string)
index.append(i.account_nm.string)
data_dic[i.account_nm.string]=i.thstrm_amount.string
print(data_dic)
print(1)
#전체 data 중 관심있는 항목만 추출
output_data={df1.index[0]:0, df1.index[1]:0, df1.index[2]:0, df1.index[3]:0, df1.index[4]:0, df1.index[5]:0, df1.index[6]:0, df1.index[7]:0, df1.index[8]:0}
if len(data_dic) != 0:
for i in df1.index:
if i in data_dic:
output_data[i]=data_dic[i]
print(i)
print('OK')
elif i == '분기순이익':
print(i)
print('NOK')
nm_list = ['당기순이익(손실)','1. 당기순이익(손실)', '당기순이익', '당기순손익', '연결당기순이익', '반기순이익(손실)', '반기순이익', 'VI.당기순손익', '당(반)기순이익',
'연결분기(당기)순이익', '연결반기순이익', '분(반)기순이익(손실)','순이익(손실)', '분기순이익(손실)', '분기순손익', '연결분기순이익']
for j in nm_list:
if j in data_dic:
output_data[i] = data_dic[j]
elif i == '자본총계':
print(i)
print('NOK')
nm_list = ['자본 총계']
for j in nm_list:
if j in data_dic:
output_data[i] = data_dic[j]
elif i == '자산총계':
print(i)
print('NOK')
nm_list = ['자산 총계']
for j in nm_list:
if j in data_dic:
output_data[i] = data_dic[j]
elif i == '부채총계':
print(i)
print('NOK')
nm_list = ['부채 총계']
for j in nm_list:
if j in data_dic:
output_data[i] = data_dic[j]
elif i == '영업이익':
print(i)
print('NOK')
nm_list = ['IV. 영업이익(손실)', '영업이익(손실)','IV.영업이익(손실)', 'IV.영업이익', '영업손실', '영업이익 (손실)']
for j in nm_list:
if j in data_dic:
output_data[i] = data_dic[j]
elif i == '매출액':
print(i)
print('NOK')
nm_list = ['수익(매출액)', '영업수익', '매출액 및 지분법손익', '매출', 'I. 매출액','I.매출액','I.매출', '수익', '영업수익(매출액)']
for j in nm_list:
if j in data_dic:
output_data[i] = data_dic[j]
elif i == '영업활동현금흐름':
print(i)
print('NOK')
nm_list = ['영업활동으로 인한 현금흐름', 'I.영업활동으로 인한 현금흐름', 'I. 영업활동으로 인한 현금흐름', '영업활동으로 인한 순현금흐름', 'I. 영업활동현금흐름', 'I.영업활동현금흐름', '영업활동 현금흐름',
'영업활동으로인한현금흐름', 'I. 영업활동 현금흐름']
for j in nm_list:
if j in data_dic:
output_data[i] = data_dic[j]
elif i == '유동자산':
print(i)
print('NOK')
nm_list = ['I.유동자산']
for j in nm_list:
if j in data_dic:
output_data[i] = data_dic[j]
elif i == '기본주당이익':
print(i)
print('NOK')
nm_list = ['지배기업의 소유주에 대한 기본및희석주당이익', '지배기업의 소유주에 대한 기본 및 희석 주당이익', '지배기업의 소유주지분에 대한 기본및희석주당이익',
'기본주당이익(손실)', '기본및희석주당이익(손실)', '기본 및 희석주당이익(손실)', '기본 주당이익', '기본 주당이익(손실)', '기본주당순이익', '기본 주당 순이익',
'지배기업의 지분에 대한 주당이익(손실)', '보통주 기본 및 희석주당순손익','보통주 기본및희석주당이익(손실)','지배기업소유주 희석 주당이익', '기본 및 희석주당이익',
'기본및희석주당손익', '기본주당손익', '기본희석주당손익', '기본 및 희석 보통주당이익',
'기본주당이익(손실) (단위:원)', '기본주당순이익(손실)', '기본주당분기순이익', '기본주당반기순이익', '주당순이익', '기본및희석주당순이익', '기본 및 희석 주당이익(손실)',
'보통주 기본주당이익', '보통주 기본주당이익(손실)', '보통주주당순손실', '보통주주당순이익(손실)',
'보통주 주당순이익', '보통주 주당순이익(손실)', '기본 및 희석 주당 이익', '지배기업지분에 대한 주당순이익', '보통주 기본주당중단영업이익', '보통주 기본 및 희석주당이익 (단위: 원)',
'보통주 기본주당손익', '보통주 기본및희석주당손익','기본 및 희석주당순이익(손실)','중단영업 기본주당순손익', '보통주 기본주당순이익','보통주기본주당중단영업이익(손실)']
nm_list_con = ['계속영업주당이익(손실)', '계속영업기본주당이익(손실)', '계속영업주당이익','계속영업주당이익(손실)','계속영업주당이익 (손실)', '계속영업기본주당순이익',
'계속및희석주당이익', '계속영업희석주당이익(손실)', '계속영업주당손익', '계속기본주당이익(손실)']
nm_list_stop = ['중단영업주당이익(손실)', '중단영업기본주당이익(손실)', '중단영업주당이익', '중단영업주당이익(손실)', '중단영업주당이익 (손실)','중단영업기본주당순이익',
'중단및희석주당이익', '중단영업희석주당이익(손실)', '중단영업주당손익', '중단기본주당이익(손실)']
a = 0
b = 0
#주당이익이 있으로 표현된 경우
for j in nm_list:
if j in data_dic:
output_data[i] = data_dic[j]
#계속 / 중단 주당이익으로 나뉘어 표현된 경우
for j in nm_list_con:
if j in data_dic:
EPS_con = float(data_dic[j])
print(type(EPS_con))
a=1
for j in nm_list_stop:
if j in data_dic:
EPS_stop=data_dic[j]
if str(type(EPS_stop)) != "<class 'NoneType'>":
EPS_stop = float(data_dic[j])
else:
EPS_stop = 0
b=1
if a+b == 2:
output_data[i] = EPS_con + EPS_stop
else:
for i in df1.index:
output_data[i]=0
print(output_data)
#데이터 프레임에 열 추가
df1[report_date]=output_data.values()
#엑셀시트 지정
wb = xw.Book('korea_stock_dart.xlsm')
sheet = wb.sheets[0]
stock_code_row=8
stock_code_column=2
while stock_code_row < 104:
# 데이터 프레임 index, 얻고자 하는 항목
data_index = {'유동자산', '자산총계', '자본총계', '부채총계', '매출액', '영업이익', '분기순이익', '영업활동현금흐름', '기본주당이익'}
# 초기값
init_value = [0, 0, 0, 0, 0, 0, 0, 0, 0]
df1 = pd.DataFrame(data=init_value, index=data_index)
stock_code=sheet.range(stock_code_row,stock_code_column).value
print(stock_code)
#2017~2020 정보요청
get_Data(stock_code,2020)
get_Data(stock_code,2019)
get_Data(stock_code,2018)
get_Data(stock_code,2017)
#초기값 삭제
del df1[0]
print(1)
print(df1)
row=1
column=67
#데이터 엑셀 위치 고정
data_position= {'유동자산':7, '자산총계':4, '자본총계':5, '부채총계':6, '매출액':3, '영업이익':2, '분기순이익':0, '영업활동현금흐름':1, '기본주당이익':8}
for i in df1.index:
column_temp = column + data_position[i] * 18
j=0
while j < len(df1.loc[i]):
sheet.range(stock_code_row, column_temp -1).value = i
sheet.range(stock_code_row,column_temp+j).value=df1.loc[i][j]
j=j+1
stock_code_row = stock_code_row +1
결과
세로 항목은 종목코드이다. (엑셀에 종목코드만 입력하면 현재 가격, 시총 등 기본 정보는 제공해준다.)
매출액을 최신 부터 오래된 데이터 순서로 정리하여 변화 추이를 확일 할 수 있도록 하였다.
'프로그래밍 > DART 재무제표 크롤링' 카테고리의 다른 글
DART 재무제표 크롤링 (0) | 2020.12.27 |
---|---|
DART 기업 코드 크롤링 (0) | 2020.12.27 |