파이썬으로 DART에서 재무제표 수집하기
이번 포스트에서는 전자공시시스템(DART)에서 제공하는 재무제표를 파이썬으로 다운로드하고 파싱하는 방법을 다룹니다.
DART에서 재무제표를 얻어오는 방법은 다양한데 여기서는 두 가지 방법을 다룹니다.
DART Open API 상장기업 재무정보
첫 번째로 단일회사 주요계정 API를 활용한 방법입니다.
DART Open API를 사용하려면 인증키가 필요합니다. 인증키 획득 방법은 이 포스트에서 확인하세요.
다음은 단일회사 주요계정 API를 호출하여 재무제표 정보를 획득하는 함수 입니다. 인증키
, 회사 고유번호
, 사업연도
, 보고서 코드
를 입력하여 재무제표를 받아올 수 있습니다.
def get_fs(crtfc_key, corp_code, bsns_year, reprt_code):
# 단일회사 주요계정
# crtfc_key API 인증키 STRING(40) Y 발급받은 인증키(40자리)
# corp_code 고유번호 STRING(8) Y 공시대상회사의 고유번호(8자리)
# ※ 개발가이드 > 공시정보 > 고유번호 API조회 가능
# bsns_year 사업연도 STRING(1) Y 사업연도(4자리)
# ※ 2015년 이후 부터 정보제공
# reprt_code 보고서 코드 STRING(5) Y 1분기보고서 : 11013
# 반기보고서 : 11012
# 3분기보고서 : 11014
# 사업보고서 : 11011
api = 'https://opendart.fss.or.kr/api/fnlttSinglAcnt.json'
params = {
'crtfc_key': crtfc_key,
'corp_code': corp_code,
'bsns_year': bsns_year,
}
data = []
reprt_name = REPRT_NAMES.get(reprt_code, "")
params['reprt_code'] = reprt_code
res = self._request(api, params=params)
if res is None:
return None
if res.status_code != 200:
return None
item = json.loads(res.text)
if item.get('status', '') != '000':
return None
for _item in item.get('list'):
_item['corp_code'] = corp_code
_item['reprt_code'] = reprt_code
_item['reprt_name'] = reprt_name
data.append(_item)
return data
get_fs(crtfc_key, '00266961', 2015, '11011')
와 같이 호출하면 다음과 같은 결과를 받아올 수 있습니다.
[{'account_nm': '자산총계', 'bfefrmtrm_amount': '9,881,190,909,324', 'bfefrmtrm_dt': '2018.12.31 현재', 'bfefrmtrm_nm': '제 20 기', 'bsns_year': '2020', 'corp_code': '00266961', 'frmtrm_amount': '12,299,527,120,786', 'frmtrm_dt': '2019.12.31 현재', 'frmtrm_nm': '제 21 기', ...}, {'account_nm': '부채총계', 'bfefrmtrm_amount': '3,932,050,396,031', 'bfefrmtrm_dt': '2018.12.31 현재', 'bfefrmtrm_nm': '제 20 기', 'bsns_year': '2020', 'corp_code': '00266961', 'frmtrm_amount': '5,795,601,052,206', 'frmtrm_dt': '2019.12.31 현재', 'frmtrm_nm': '제 21 기', ...}, ...]
DART Open API 재무정보 일괄 다운로드
두 번째는 재무정보 일괄 다운로드로 한꺼번에 전체 기업의 재무제표 데이터를 받아오는 방법입니다. Open DART 사이트에서 공시정보 활용마당 / 재무정보 일괄다운로드
를 클릭하면 다음과 같은 테이블을 볼 수 있습니다.
여기서 다운로드 하면 해당 연도와 분기의 네 종류의 재무제표를 압축파일로 다운 받을 수 있습니다. 여기서는 다운로드, 압축해제를 포함하여 파이썬에서 재무제표를 읽어오는 방법을 다룹니다.
다음은 Selenium으로 다운로드
버튼을 클릭하여 파일을 다운로드하고 압축을 해제하는 코드입니다.
options = webdriver.ChromeOptions()
options.add_experimental_option("prefs", {
"download.default_directory": self.job_base,
"download.prompt_for_download": False,
"download.directory_upgrade": True,
"safebrowsing.enabled": True
})
options.add_argument("disable-infobars")
options.add_argument("--disable-extensions")
browser = webdriver.Chrome(executable_path=os.path.join(settings.QUANTYLAB_BASE, 'drivers/chromedriver'), chrome_options=options)
try:
browser.get('https://opendart.fss.or.kr/disclosureinfo/fnltt/dwld/main.do')
elem = browser.find_element_by_css_selector('table.tb01')
for elem_a in elem.find_elements_by_link_text('다운로드'):
filename = re.findall(r'.*\(.*\'(.+)\'\).*', elem_a.get_attribute('onclick'))[0]
# 파일 다운로드
elem_a.click()
time.sleep(10)
# 압축파일 로드
filepath = os.path.join(base, filename)
z = zipfile.ZipFile(filepath)
for info in z.infolist():
# 한글 파일명 인코딩 수정
_filename = info.filename.encode('cp437').decode('euc-kr')
_filepath = os.path.join(base, _filename)
if os.path.exists(_filepath):
continue
info.filename = _filename
# 압축해제
z.extract(info, base)
z.close()
except Exception as e:
print(str(e))
finally:
browser.quit()
이렇게 압축해제까지 하면 2020_1분기보고서_04_현금흐름표_20210211.txt
과 같은 파일들이 생성되어 있을 것입니다.
이 텍스트 파일은 다음과 같이 pandas로 쉽게 DataFrame
으로 읽어올 수 있습니다. 다만 sep
과 encoding
을 다음과 같이 적절하게 정해주는 것이 중요합니다.
df = pd.read_csv(filepath, sep='\t', encoding='cp949')
여기서 당기
, 당기 1분기
, 당기 반기
등의 다양한 컬럼이 생기는데 저는 이들을 당기
로 통합하여 정리했습니다.
다음은 포괄손익계산서
의 일부 항목을 나타낸 것입니다.
항목명 | 결산기준일 | 보고서종류 | 당기 |
---|---|---|---|
영업수익 | 2018-12-31 | 사업보고서 | 5,586,904,533,355 |
영업이익(손실) | 2018-12-31 | 사업보고서 | 942,532,561,543 |
당기순이익(손실) | 2018-12-31 | 사업보고서 | 627,901,873,332 |
그런데 재무제표를 볼 때 항목의 흐름을 보는 것이 중요합니다. 예를 들어 영업 이익이 꾸준히 증가하고 있는지를 보고 싶은 것입니다.
그래서 동일 항목에 대해서 결산기준일 순서대로 DataFrame
을 재구성하고자 합니다. 이를 위해 DataFrame
의 pivot
함수를 사용합니다.
df_pivot = df.pivot(values='value', index='항목명', columns='결산기준일')
동일 항목이지만 항목명이 다르게 적혀있는 경우가 있어서 이를 맞춰주는 처리를 했습니다.
그럼 다음과 같이 동일 항목의 값을 분기 순서대로 볼 수 있습니다.
항목명 | 2015-12-31 | 2016-03-31 | 2016-06-30 | 2016-09-30 | 2016-12-31 | 2017-03-31 | 2017-06-30 | 2017-09-30 | 2017-12-31 | 2018-03-31 | 2018-06-30 | 2018-09-30 | 2018-12-31 | 2019-03-31 | 2019-06-30 | 2019-09-30 | 2019-12-31 | 2020-03-31 | 2020-06-30 | 2020-09-30 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
매출액 | 3,251,157,100,000 | 937,280,220,152 | 987,281,364,295 | 1,013,075,223,770 | 4,022,629,619,982 | 1,082,247,281,196 | 1,129,631,366,847 | 1,200,676,275,220 | 4,678,468,928,032 | 1,309,059,864,248 | 1,363,615,953,332 | 1,397,713,834,674 | 5,586,904,533,355 | 1,510,861,770,282 | 1,630,275,004,395 | 1,664,815,000,078 | 6,593,400,065,244 | 1,732,064,462,097 | 1,902,467,957,491 | 1,360,779,374,259 |
영업이익 | 762,203,849,000 | 256,827,536,675 | 272,663,961,847 | 282,298,051,525 | 1,102,040,475,792 | 290,797,289,304 | 285,213,522,180 | 312,084,238,444 | 1,179,187,806,331 | 256,980,563,870 | 250,583,189,279 | 221,718,402,565 | 942,532,561,543 | 206,244,504,954 | 128,334,709,480 | 202,086,039,366 | 710,070,173,513 | 221,495,078,328 | 230,597,573,115 | 291,726,798,004 |
당기순이익 | 516,986,279,000 | 165,036,146,535 | 213,223,506,226 | 198,000,157,034 | 759,072,951,187 | 210,876,050,870 | 171,420,229,303 | 215,798,264,368 | 770,101,670,207 | 153,751,654,038 | 281,758,577,701 | 68,386,763,908 | 627,901,873,332 | 87,585,903,290 | 27,756,852,975 | 85,268,053,088 | 396,821,062,465 | 134,874,581,865 | 90,682,203,810 | 235,342,965,699 |