---
title: "DART Open API 사용"
subtitle: "FMB819: R을 이용한 데이터분석"
author: "고려대학교 경영대학 정지웅"
format: 
  revealjs:
    theme: simple
    transition: fade
    transition-speed: fast
    scrollable: true
    chalkboard: true
    slide-number: true
revealjs-plugins:
  - revealjs-text-resizer # Thanks to https://github.com/gadenbuie/revealjs-text-resizer#readme
---

```{r setup, include = FALSE, warning = FALSE, message = FALSE}
options(htmltools.dir.version = FALSE)
knitr::opts_chunk$set(
  message = FALSE,
  warning = FALSE,
  dev = "svg",
  cache = TRUE,
  fig.align = "center",
  comment = "##"
  #fig.width = 11,
  #fig.height = 5
)

# Load packages
library(tidyverse)
library(pander)
library(ggthemes)
library(gapminder)
library(countdown)
library(xaringanExtra)
```


## API(Application Programming Interface) 개요

- 금융 데이터 분석에서 API는 데이터 소스(금융감독원 DART)와 사용자(분석가) 사이의 **규약된 통로**. 웹 브라우저에서 눈으로 데이터를 확인하는 대신, 프로그래밍 코드를 통해 필요한 데이터만 직접 요청하고 구조화된 형태로 받을 수 있음.

### API의 핵심 요소
- **Endpoint (URL)**: 데이터가 저장된 주소 (예: `https://opendart.fss.or.kr/api/...`)
- **Authentication (인증키)**: 허가된 사용자임을 증명하는 고유 Key.
- **Request Parameters (요청 인자)**: 수집하고 싶은 데이터의 조건 (기업코드, 기간, 보고서 종류 등).
- **Response (응답 데이터)**: 서버가 돌려주는 데이터로, 주로 **JSON** 또는 **XML** 형식을 사용합니다.

---

## DART Open API의 특징과 체계

- 금융감독원 전자공시시스템(DART)은 상장법인 등의 공시 서류를 제공. Open API를 사용하면 수천 개 기업의 데이터를 반복적으로 수집하는 과정을 자동화할 수 있음.

### 주요 제공 데이터 (API 그룹)
1.  **공시 검색 (DS001)**: 특정 기간 내 발생한 공시 목록 조회.
2.  **기업 개황 (기업 정보)**: 업종, 주소, 상장 여부 등 기본 정보.
3.  **상장기업 재무정보**: 주요 재무제표 항목.
4.  **단일회사 전체 재무제표**: 특정 시점의 전체 재무제표(XBRL 데이터 포함).
5.  **사업보고서 주요 정보**: 배당, 최대주주 현황, 임원 연봉 등.

---

## 사전 준비 및 인증키 설정

- DART 데이터를 받기 위해서는 [DART Open API 홈페이지](https://opendart.fss.or.kr/)에서 인증키(API Key)를 발급받아야 함.

1.  API Key를 `.Renviron` 파일에 추가. 다음 명령을 실행
```r
file.edit("~/.Renviron")
```
2. `DART_API_KEY="발급받은_키_번호"`을 적어서 저장.
    - 윈도우에서는 일반적으로 `"C:\Users\[사용자명]\Documents\.Renviron"` 에 저장이 됨.
    - 이름이 `.`으로 시작하는 파일은 윈도우나 맥 탐색기에서 기본적으로 숨겨져(Hidden) 있음. 

3. 파일을 저장한 뒤 R을 재시작
    - `.Renviron` 파일은 R이 시작될 때 딱 한 번 읽어옴
4. 인증키 불러오기
```r
dart_api_key <- Sys.getenv("DART_API_KEY")
```


--- 

## 사전 준비 및 인증키 설정

```{r}
#| label: dart-setup
#| eval: False
#| echo: True

# 필요한 R 패키지 로드
library(httr)
library(jsonlite)
library(xml2)
library(stringr)
library(dplyr)

# API 인증키 설정
dart_api_key <- Sys.getenv("DART_API_KEY")
```

- **"이 패키지들은 하나의 조립 라인(Assembly Line)과 같음"** 
    - `httr`로 원재료(데이터)를 가져오고, `xml2/jsonlite`로 포장을 뜯고, `rvest`로 알맹이를 골라내며, `stringr`로 예쁘게 다듬어 최종 데이터프레임을 만듬.

---

## 필요 패키지 {background-color="#ebf8ff"}

1. `library(httr)`: 데이터 운반 (HTTP Request)
    - R과 DART 서버 사이의 통신을 담당.
    - "이 URL로 데이터를 보내줘"라고 요청하는 GET() 함수를 제공. 브라우저 주소창에 주소를 치고 엔터를 누르는 행위를 코드로 대신해 주는 도구.

2. `library(xml2)`: 데이터 추출 (Scraping/Harvesting)
    - 웹페이지나 XML 문서에서 필요한 정보만 골라내기 위해 사용.
    - DART에서 받은 XML 파일 안에는 수많은 태그들이 섞여 있음. 이 중 우리가 원하는 corp_code나 stock_code 같은 특정 항목만 집어낼 때(xml_find_all, xml_text) 필수적.

3. `library(jsonlite)`: 데이터 해석 (JSON Parsing)
    - 서버로부터 받은 JSON 형식의 텍스트를 R 객체로 변환.
    - 최근 대부분의 현대적 API(DART 포함)는 데이터를 JSON 형태로 응답. `fromJSON()` 함수 한 줄이면 복잡한 텍스트 뭉치를 R에서 바로 분석 가능한 **데이터프레임**으로 바꿔줌.

4. `library(stringr)`: 데이터 정제 (String Manipulation)
    - 텍스트 데이터의 가공과 수정을 담당.
    - 금융 데이터 분석에서 가장 빈번한 오류 중 하나가 0으로 시작하는 종목코드 처리. (예: 삼성전자 '005930'이 '5930'으로 읽히는 경우). `str_pad()` 함수 등을 사용하여 자릿수를 맞추거나, URL 주소 문자열을 깔끔하게 조립할 때 매우 유용.

---

## 실습: 기업 고유번호(Corp Code) 수집

- DART API는 주식 시장의 '종목코드(6자리)' 대신 자체적인 **'고유번호(8자리)'**를 사용. 따라서 종목코드와 고유번호를 매칭하는 과정이 선행되어야.

- 고유번호 파일 다운로드 및 파싱
    - DART는 모든 기업의 고유번호를 하나의 ZIP 파일(XML 포함) 형태로 제공.

- [https://opendart.fss.or.kr/guide/detail.do?apiGrpCd=DS001&apiId=2019018](https://opendart.fss.or.kr/guide/detail.do?apiGrpCd=DS001&apiId=2019018)

```{r}
#| label: get-corp-code
#| eval: False
#| echo: True

# 1. 고유번호 파일 요청 URL
codezip_url <- paste0('https://opendart.fss.or.kr/api/corpCode.xml?crtfc_key=', dart_api_key)

# 2. 데이터 다운로드
response <- GET(codezip_url)

# 3. 데이터 수령 -> 저장 -> 압축 해제 -> 내용 판독
tf <- tempfile(fileext = '.zip')
writeBin(content(response, as = "raw"), tf)

# 압축 파일 내의 파일 목록 확인
nm <- unzip(tf, list = TRUE)

# 임시 폴더(tempdir)에 압축 해제하여 작업 공간 오염 방지
extracted_file <- unzip(tf, files = nm$Name[1], exdir = tempdir())

# XML 읽기
code_data <- read_xml(extracted_file)

# 4. 데이터프레임 변환
corp_code <- code_data %>% xml_find_all('//corp_code') %>% xml_text()
corp_name <- code_data %>% xml_find_all('//corp_name') %>% xml_text()
stock_code <- code_data %>% xml_find_all('//stock_code') %>% xml_text()

corp_list <- data.frame(
  code = corp_code,
  name = corp_name,
  stock = stock_code,
  stringsAsFactors = FALSE
)

# 상장사(stock_code가 6자리인 기업)만 필터링 (공백 문자가 들어올 수 있으므로 trimws())
corp_list_listed <- subset(corp_list, nchar(trimws(stock)) == 6)

# 5. 메모리 정리 (임시 파일 삭제)
unlink(tf)
unlink(extracted_file)

# 6. 결과 확인
head(corp_list_listed)
```


---

## 명령어 의미 {background-color="#ebf8ff"}

1. `tf <- tempfile(fileext = '.zip')`
    - 임시 저장 공간(빈 상자) 만들기
    - 컴퓨터에 데이터를 잠시 보관할 임시 파일 경로를 생성. 이름이 .zip으로 끝나는 일회용 빈 상자를 하나 준비하는 것과 같음. 작업 폴더를 지저분하게 만들지 않고 메모리 효율을 높이기 위해 사용.

2. `writeBin(content(response, as = "raw"), tf)`
    - 받은 데이터를 상자에 담기
    - DART 서버에서 보내준 **원시 이진 데이터(Raw Binary)**를 위에서 만든 임시 파일(tf)에 실제로 저장. API로부터 받은 "디지털 택배물"을 상자에 물리적으로 채워 넣는 단계.

3. `nm <- unzip(tf, list = TRUE)`
    - 압축 파일 내부 명단(송장) 확인
    - 압축을 실제로 풀기 전에, 그 안에 어떤 파일들이 들어있는지 목록만 확인. DART 고유번호 ZIP 파일 안에는 보통 CORPCODE.xml이라는 파일이 들어있는데, 이 파일의 이름을 정확히 알아내기 위해 사용.

4. `code_data <- read_xml(unzip(tf, nm$Name, exdir = tempdir()))`
    - 내용물 꺼내서 읽기
    - `unzip(tf, nm$Name, exdir = tempdir())`: 상자 안에서 실제 데이터 파일(CORPCODE.xml)만 압축을 풀어 꺼냄. 임시폴더에 저장
    - `read_xml(...)`: 꺼낸 XML 파일을 R이 읽을 수 있는 구조화된 데이터 객체로 변환.

---

## 명령어 의미 {background-color="#ebf8ff"}

1. `xml_find_all('태그이름')`:
    - 수많은 데이터 중 특정 이름표(태그)가 붙은 것들만 하이라이트.
    - 거대한 엑셀 시트에서 특정 열(Column) 전체를 마우스로 드래그하는 것과 같음.

2. `xml_text()`:
    - 하이라이트 된 부분에서 `<tag>...</tag>` 같은 XML 문법 기호는 버리고, 그 안의 순수한 글자만 추출.
    - 귤 껍질(태그)을 까서 알맹이(텍스트)만 남기는 과정.
    
---


## 실습: 재무제표 데이터 추출
- 특정 기업의 재무 상태를 분석하기 위해 '상장기업 재무정보' API를 활용하여 주요 항목을 가져옴.

- 주요 요청 인자 (Parameters): 
    - `bsns_year`: 사업연도 (예: 2023)
    - `reprt_code`: 보고서 코드 (1분기: 11013, 반기: 11012, 3분기: 11014, 사업보고서: 11011)
    
- [https://opendart.fss.or.kr/guide/detail.do?apiGrpCd=DS003&apiId=2019016](https://opendart.fss.or.kr/guide/detail.do?apiGrpCd=DS003&apiId=2019016)


```{r}
#| label: get-financial-data
#| eval: False
#| echo: True

# 삼성전자(고유번호: 00126380)의 2023년 사업보고서 재무제표 요청
target_corp <- "00126380"
# 수정 후:
url <- paste0("https://opendart.fss.or.kr/api/fnlttSinglAcnt.json?",
              "crtfc_key=", dart_api_key,
              "&corp_code=", target_corp,
              "&bsns_year=2023",
              "&reprt_code=11011")

# JSON 데이터 수집 및 변환
data_json <- fromJSON(url)
financial_table <- data_json$list

# 주요 항목 확인 (자산총계, 매출액, 당기순이익 등)
financial_table[, c("account_nm", "fs_nm", "thstrm_nm", "thstrm_amount")]
```

---

# THE END