본문 바로가기

Projects/재태크

[VBA] DART 재무제표 크롤러

구현 사례

 

왜 만들었는가 

  • 지인의 부탁으로 만들게 되었다.
  • 의뢰인은 상장사 여러 곳의 재무제표를 가져올 일이 있는데, 매번 사이트에 가서 재무제표 가져오기를 클릭하는 것이 무척 번거로워 이를 효율적으로 할 수 있는 방법이 없는지 문의해주셨다.
  • 처음에는 VBA 말고 파이썬의 OpenDartReader 라이브러리를 사용해 보려고  했다. 하지만 실제로 사용을 해보니 재무제표를 가져오는 작업이 매우 매우 느리다. 도저히 속도가 답답해서 직접 코드를 작성해 보았다.

프로젝트 개요

  1. 유저가 업체명,연도,유형 등 필요한 사항을 기입한다.
  2. 코드는 이를 input 변수로 인식하고, 우선 DART OPEN API를 이용해서 해당 사업보고서의 문서정보를 가져온다. DART OPEN API의 응답 형태는 JSON이기 떄문에 문서 정보를 가져오기 위해서는 VBA-JSON 이라는 외부 라이브러리를 활용해야 한다. (https://github.com/VBA-tools/VBA-JSON)
  3. 문서정보가 있으면 이를 바탕으로 엑셀 파일을 DART 서버에 직접 요청해서 다운로드한다.

구현 코드

Sub download_dart()

Dim JSON As Object
Dim i, lr, year As Long
Dim apikey, doc_type, comp_code, start_date, end_date As String
Dim url1, url2, url3, url4, url5, final_url As String
Dim doc_num, download_url As String
Dim mydir, comp_name, doc_type_name As String
Dim oStream As Object

'여기에 재무제표를 저장할 폴더 경로 삽입.
mydir = "C:\Users\test\"

'여기에 개인 key 넣기 개인 Api 발급은 https://opendart.fss.or.kr/intro/main.do 이용
apikey = ""


lr = Worksheets(1).Cells(Rows.Count, 3).End(xlUp).Row

For i = 5 To lr
    comp_name = Worksheets(1).Cells(i, 3).Value
    comp_code = Application.WorksheetFunction.VLookup(Cells(i, 3).Value, Worksheets(2).Range("a1:e83371"), 3, False)
    
    year = Worksheets(1).Cells(i, 4).Value
    doc_type_name = Worksheets(1).Cells(i, 5).Value
    doc_type = Application.WorksheetFunction.VLookup(Cells(i, 5).Value, Worksheets(3).Range("a1:d5"), 2, False) 'A003
    If doc_type <> "A001" Then
        start_date = CStr(year) & Application.WorksheetFunction.VLookup(Cells(i, 5).Value, Worksheets(3).Range("a1:d5"), 3, False)
        end_date = CStr(year) & Application.WorksheetFunction.VLookup(Cells(i, 5).Value, Worksheets(3).Range("a1:d5"), 4, False)
    Else
        start_date = CStr(year + 1) & Application.WorksheetFunction.VLookup(Cells(i, 5).Value, Worksheets(3).Range("a1:d5"), 3, False)
        end_date = CStr(year + 2) & Application.WorksheetFunction.VLookup(Cells(i, 5).Value, Worksheets(3).Range("a1:d5"), 4, False)
    End If
    
    url1 = "https://opendart.fss.or.kr/api/list.json?crtfc_key="
    'apikey
    url2 = "&pblntf_detail_ty="
    'doc_type
    url3 = "&corp_code="
    'comp_code
    url4 = "&bgn_de="
    'start_date
    url5 = "&end_de="
    'end_date
    final_url = url1 & apikey & url2 & doc_type & url3 & comp_code & url4 & start_date & url5 & end_date
    Cells(i, 6).Value = final_url
    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", final_url, False
        .send
        Set JSON = JsonConverter.ParseJson(.responseText)
    End With
    If JSON("message") = "조회된 데이타가 없습니다." Then
        Cells(i, 6).Value = "보고서가 없습니다"
    Else
        Cells(i, 6).Value = "다운로드 완료"
        doc_num = JSON("list")(1)("rcept_no")
        download_url = "http://dart.fss.or.kr/pdf/download/excel.do?lang=ko&rcp_no=" & doc_num
        
        Dim WinHttpReq As Object
        Set WinHttpReq = CreateObject("MSXML2.XMLHTTP")
        WinHttpReq.Open "GET", download_url, False
        WinHttpReq.send
        
        If WinHttpReq.Status = 200 Then
            Set oStream = CreateObject("ADODB.Stream")
            oStream.Open
            oStream.Type = 1
            oStream.Write WinHttpReq.responseBody
            oStream.SaveToFile mydir & comp_name & "_" & CStr(year) & "_" & doc_type_name & ".xls", 2 ' 1 = no overwrite, 2 = overwrite
            oStream.Close
        End If
        
    End If
Next


End Sub

 

코멘트

  • 엑셀 VBA로도 파이썬보다 더 사용하기 편한 프로그램을 만들 수 있다. 특히 원래 작업 자체가 엑셀 기반인 경우 VBA로 프로그램을 구현하는 것이 효율적일 수 있다. (사용자는 엑셀이라는 프로그램 안에서 크롤링 및 데이터 가공을 모두 한번에 수행할 수 있다.)]
  • VBA의 Microsoft Scripting Runtime(딕셔너리 자료형태를 인식하게 해줌, VBA-JSON과 함께 쓰임)와 XML 6.0 라이브러리는 크롤링에서 정말 필수적이다. 특히 대부분의 response type이 JSON인 상황에서 이 두 라이브러리가 있으면 대부분의 크롤링 작업을 수행할 수 있다. 
  • Microsoft Scripting Runtime과 XML 6.0은 윈도우 엑셀에서는 기본으로 내장된 라이브러리여서, 도구-참조에 들어가서 체크를 하면 바로 사용이 가능한데 맥OS 엑셀에서는 기본으로 탑재되어 있지 않다. 맥OS로 VBA 프로그래밍이 정말 싫어지는 이유 중 하다.