2020년 1월 22일 기준 전자공시사이트(dart.fss.or.kr)에서 신규API사이트 오픈을 공개했다.
그간 개발해온 프로젝트와 동일한 목적을 이루는 API 또한 존재하는 걸 확인했고, 이를 테스트 해본 결과 더 양질의 결과물을 얻을 수 있는 것을 확인했다.
그렇다. 위의 말을 정리하자면 그간 진행해온 사항들이 물거품이 된 것이다!
이 때문에 갈피를 잃은 나는 앞으로 프로젝트를 어떻게 진행해야 하는지에 대한 깊은 고민에 빠졌었다.
대리님께도 말씀 드려보고, 차장님께도 시연을 보여드렸는데 모두 ‘신규 API를 이용할 수 밖에 없겠네.’ 라는 반응이셨다.
그도 그럴 것이,
이 정도의 퀄리티 차이가 나타나다보니…
그래도 진행해야만 하는 것이 프로젝트니까, 초심을 다 잡고 처음부터 다시 접근해보기로 했다.
“이 프로젝트가 회사에 필요한 이유가 무엇이었지?”
프로젝트를 진행하던 당시 프로젝트를 제안해주신 IT파트 차장님과, 실제 이 프로젝트 소식을 듣고 기대하시는 총무파트 사원님의 기대하시는 방향이 서로 달랐었다. IT파트 차장님께서는 ‘웹 크롤링의 여러가지 활용 방안’ 이 주 기대 사항이셨고, 총무파트 사원님은 ‘실제 구매/총무/재무 쪽 부서 직원분들이 재무정보를 참고할 때, 혹은 IT부서 직원분들이 재무정보를 EIS에 삽입할 때 수 많은 절차를 단순 반복 작업 (노가다) 하는 과정을 단축시키는 것’ 이 주 기대 사항이셨다.
나는 현재 IT파트 차장님의 의견을 주 목적으로 삼고 프로젝트를 진행하다가, 훨씬 뛰어난 결과물을 내는 신규 API로 인해 웹 크롤링의 필요성을 상실하였기 때문에 을 겪고 있었다. 주 목적을 총무파트 사원님의 의견으로 바꾸면 다르게 생각해볼 기회가 열리는 것이었다.
“그렇다면 웹 크롤링이 조금이라도 포함되면서 생산성을 향상시킬 수 있는 방향에는 무엇이 있을까?”
의외로 쉽게 답을 구할 수 있었다. 바로 신규API를 활용한 재무재표파일 다운로드 자동화 그리하여 일주일간의 방황 후 겨우 재분석 및 재설계를 시작하였다.
분석 및 설계
- OpenDART 사이트 공지 및 오픈
- 기존 개발 중이던 프로그램과 비교 진행, 개선된 결과 획득 가능
- 기존 DART API에서 OpenDART API로 변경 구상
- 기존 계획했던 프로그램을 두 가지로 분리
- OpenDART API를 활용한 재무상태표 엑셀파일 다운로드 프로그램
- OepnDART API를 활용한 재무상태표 TSV파일 다운로드 및 자동편집 프로그램
-
OpenDART API 가이드 분석 진행
- OpenDART API에서 추가적으로 요구하는 ‘기업고유번호’에 관한 고찰
- ‘기업고유번호’는 ‘기업종목코드’와 서로 다른 값
- DART전자공시사이트 데이터베이스에서 key값으로 사용되는 번호로 추정
- 기업고유번호 획득을 위해서는 OpenDART API에서 제공되는 xml파일이 필요
- OpenDART API를 활용한 재무상태표 엑셀파일 다운로드 프로그램 개발 완료
작성 코드
from bs4 import BeautifulSoup # for html parser
from urllib.request import urlopen # for html request/respone
import pandas as pd # for DataFrame
import webbrowser # for open the Excel file download link
import xml.etree.ElementTree as eTree # for read xml file
import sys # for handling
urlopen을 통해 url주소를 열고, BeautifulSoup4 를 통해 html태그를 기준으로 소스코드를 읽어들인다.
읽어들인 내용들 중 필요한 내용만 쉽게 분별하기 위해서 pandas 모듈을 사용했고,
webbrowser 모듈을 통해 파일 다운로드를 진행했다.
etree 모듈의 경우 OpenDART API에서 제공되는 xml파일을 읽어야했으므로 필요했다.
sys모듈은… 에러시 강제종료를 위했던거라 딱히 필요하진 않았다.
API_KEY = "" # API 이용에 필요한 인증번호
COMPANY_CODE = input("기업종목코드 6자리 : ")
OpenDART API 역시 인증번호를 필요로 한다.
기업종목코드의 경우 xml파일에서 기업고유번호를 탐색하기 위해 필요했다.
def get_rcp_no() : # 기업종목코드 기반 보고서번호를 얻기 위한 함수
SEARCH_URL = "http://dart.fss.or.kr/api/search.xml?auth=" + API_KEY + "&crp_cd=" + COMPANY_CODE
SEARCH_URL = SEARCH_URL + "&start_dt=19990101&bsn_tp=A001&fin_rpt=Y" #검색날짜 범위 / 사업보고서 / 최종보고서만
XML_RESULT = BeautifulSoup(urlopen(SEARCH_URL).read(), 'html.parser')
find_list = XML_RESULT.findAll("list") # list태그를 모두 탐색
data = pd.DataFrame() # 데이터를 저장할 프레임 선언
for t in find_list : # 나열번호, 기업명, 기업번호, 보고서명, 보고서번호, 제출인, 접수일자, 비고
temp = pd.DataFrame(([[t.crp_cls.string, t.crp_nm.string, t.crp_cd.string, t.rpt_nm.string,
t.rcp_no.string, t.flr_nm.string, t.rcp_dt.string, t.rmk.string]]),
columns = ["crp_cls", "crp_nm", "crp_cd", "rpt_nm", "rcp_no", "flr_nm", "rcp_dt", "rmk"])
data = pd.concat([data, temp])
if len(data) < 1 : # 검색 결과가 없을 시.
print("!!! 에러 : 사업보고서 없음")
sys.exit()
return data['rcp_no'] # rcp_no 에 대한 정보만 넘김.
동작별로 묶어 함수형태로 코드를 작성해보았다.
우선적으로 기업이 DART사이트에 업로드한 사업보고서의 번호를 필요로 하기 때문에
이를 획득하기 위한 함수를 작성했다.
보고서 번호 획득에는 기존 DART API를 그대로 활용하여 진행했다.
start_dt를 통해 검색날짜 범위를 지정해주고 (end_dt는 지정하지 않으면 오늘까지 검색한다.)
bsn_tp를 A001로, 사업보고서만 검색하게 했다.
fin_rpt에 Y를 주어서 최종수정된 보고서만 확인할 수 있도록 했다.
검색결과를 확인해보면 나열번호, 기업명, 기업번호, 보고서명, 보고서번호, 제출인, 접수날짜, 비고 가 나오는데
이 중에 보고서 번호인 rcp_no 값만 반환하도록 했다.
def corp_code() : # xml 파일에서 기업종목코드가 일치하는 기업고유번호 탐색
tree = eTree.parse("CORPCODE.xml").findall('list') #xml 파일 열기 및 list 태그 기준 정렬
for CC in tree : # list 태그 기준으로 정렬된 배열 탐색
if CC.find('stock_code').text == COMPANY_CODE : # 기업종목코드가 일치한다면?
return CC.find('corp_code').text # 기업고유번호를 반환
return None # 다 돌렸으나 못 찾을 경우 None 반환
OpenDART사이트에서 제공되는 xml파일에서, 기업종목코드를 이용해 기업고유번호를 탐색하는 함수다.
eTree 모듈을 통해서 list태그 기준으로 정렬하고, list태그 내부를 모두 탐색하여 일치하는 기업종목코드를 찾아낸다.
xml 파일 내부는 아래와 같이 구성 되어있다.
<?xml version="1.0" encoding="UTF-8"?>
<result>
<list>
<corp_code>00*34003</corp_code>
<corp_name>다*</corp_name>
<stock_code> </stock_code>
<modify_date>20170630</modify_date>
</list>
<list>
<corp_code>0043*456</corp_code>
<corp_name>일산*품</corp_name>
<stock_code> </stock_code>
<modify_date>20170630</modify_date>
</list>
<list>
<corp_code>0045*265</corp_code>
<corp_name>스틸플*워</corp_name>
<stock_code>087*20</stock_code>
<modify_date>20190213</modify_date>
</list>
.
.
.
혹시 몰라서 기업명과 기업고유번호, 기업종목코드를 중간에 별표처리했다.
corp_code는 기업고유번호, stock_code는 기업종목코드를 의미한다.
살펴보면 기업고유번호는 무조건 적혀있지만 기업종목코드는 비어있는 경우가 있는데,
이런 경우 해당 기업이 아직 상장등록 되어있지 않기 때문에 그렇다.
상장등록되어있지 않은 기업은 사업보고서를 명시할 의무 또한 없기 때문에
사업보고서가 업로드되어 있지 않은 경우가 대다수다.
때문에 굳이 그런 기업들은 다운로드를 진행할 필요가 없어서 문제는 발생하지 않는다.
반환값을 None으로 하여 해결한다.
def main() : # 기본 프로그램 동작 함수
rcpNo = get_rcp_no()
CORP_CODE = corp_code()
count = 0
for RCPNO in rcpNo : # 사업보고서 갯수만큼 반복
count += 1 # URL 합성, 콘솔 화면에 몇 개의 파일을 다운로드 했는지 표기하기 위한 count
DOWN_URL = "http://dart.fss.or.kr/pdf/download/excel.do?rcp_no=" + RCPNO + "&dcm_no=" + CORP_CODE + "&lang=ko"
webbrowser.open(DOWN_URL) # 합성된 URL 열기
print("------------------------------------------------------------")
print("총 " + str(count) + "개의 사업보고서 Excel파일을 다운로드 하였습니다.")
return None
main()
마지막으로 전체 함수를 실행하는 Main함수다.
get_rcp_no함수를 실행해서 보고서번호를 list형태로 받아오고, corp_code함수를 실행해서 기업고유번호를 받아온다.
보고서번호 갯수만큼이 사업보고서 갯수를 의미하므로 이를 반복문으로 묶고,
OpenDART에서 공개한 신규 API를 통해서 다운로드를 진행한다.
rcp_no에는 보고서번호, dcm_no에는 기업고유번호, lang는 ko로 입력하여 한국어 파일을 받아온다.
만일 lang을 en으로 할 경우, 영문으로 작성된 사업보고서를 다운받을 수 있다.
완성된 URL을 webbrowser 모듈을 이용해 여는 것으로 자동 다운로드를 진행한다.
결과화면
% python3 OpenDART_API_Excel_Download.py
기업종목코드 6자리 : ******
------------------------------------------------------------
총 8개의 사업보고서 Excel파일을 다운로드 하였습니다.
기업별로 업로드 되어있는 사업보고서를 전체 다운로드 한다.
다운로드 방식은 기본 브라우저로 등록되어 있는 브라우저에 따라 다르다.
크롬의 경우 즉각적으로 다운로드를 실행하고, 익스플로러의 경우 다운로드를 확인 받는듯?
고찰 및 후기
무너진 멘탈을 부여잡는 것이 가장 중요했다.
학교 프로젝트를 진행하면서 자잘자잘한 기획 수정은 경험해보았지만, 전체적인 프로젝트 변경은 처음이라 충격이 컸다.
‘프로젝트가 엎어졌다’ 라는 표현이 가장 자주 떠올랐다. 하지만 그런들 어찌하랴, 결국 나아가야 하는 것을…
마음을 다잡기 시작했을 땐 오히려 이전보다 더 이성적으로 계획을 세우기 시작했다. 내가 왜 이 프로젝트를 진행하게 되었는지,
프로젝트의 의의가 무엇인지에 대해 더 깊게 고민하고, 설계를 더 명확하게 구체화해나갔다.
결국 보름을 넘게 진행하던 프로젝트는 일주일만에 완성할 수 있는 간단한 프로그램으로 마무리 되었다.
준비해오던 것들이 쓸모없게 된 것은 속 쓰리지만, 좋은 경험이었다고 여길 수 밖에…
앞으로도 사회에 나가 일을 진행할 때 비슷한 일을 겪게 될텐데, 대처하는 법을 배운것도 같다.
가장 좋은건 이런식으로 뒤집히지 않을 짱짱한 기획안을 받는 것이겠지만!
사람 일은 아무도 모르는 거니까.
댓글남기기