Dart에서 원하는 기업의 재무제표를 다운로드하기
아래의 두 코드를 기반으로 내 목적에 맞게 수정하였다.
Dart는 취준생, 현업자 관계없이 자주 사용하는 사이트이다. 기업의 정기/분기/반기 보고서 또한 여기에 수록되는데, 홈페이지에서 직접 다운로드 받알 수 있으나 너무 오랜 시간이 소요된다.
(사진출처: http://henryquant.blogspot.com/2019/02/r-dart-api.html)
따라서 아래의 코드를 실행시키면 저절로 10년치 자료가 받게 하는 걸 목적으로 한다.
report_down("하이닉스")
(받아진 파일 리스트)
(개별 파일을 열었을 때)
추가적으로 몇 가지 변형 또한 할 수 있다.
report_down("하이닉스") #10년치 정기공시
report_down("하이닉스", type=1) #10년치 정기공시(default)
report_down("하이닉스", type=2) #10년치 반기공시
report_down("하이닉스", type=3) #10년치 분기공시
report_down("현대", type=1) #다운로드 수행하지 않음 #'현대'라는 이름으로는 여러 종목코드 존재
report_down("현대", type=1, force=T) #여러 종목코드 중에서 첫 번째 종목의 보고서를 다운받게 할 수 있음
단계별로 살펴보도록 하자.
- 필요패키지
library(rvest)
library(httr)
library(dplyr)
library(jsonlite)
- 네이버금융에서 주식티커 크롤링
아래 function을 실행하면 ticker_list라는 종목코드 리스트를 다운받고자 한다.
download()
아래는 function의 코드다.
download <- function() {
data <- list() #1. 전체 내용이 최종적으로 담기게 될 empty list 생성
for (i in 0:1) { #2. (i=0 코스피) (i=1 코스닥) 리스트에 각각 담고 나중에 do.call rbind로 합칠 예정
ticker <- list() #1) 페이지별 정보가 바로 이 리스트에 담기게 됨
url <- #(1) 코스피/코스닥 종목리스트 첫 페이지 url
paste0('https://finance.naver.com/sise/',
'sise_market_sum.nhn?sosok=',i,'&page=1')
down_table = GET(url)
#(2) 최종 페이지 번호 찾아주기
navi.final <-
read_html(down_table, encoding = "EUC-KR") %>%
html_nodes(., ".pgRR") %>%
html_nodes(., "a") %>%
html_attr(.,"href") %>% #여기에 번호가 숨겨져 있음
strsplit(., "=") %>% #번호만 뽑아내는 작업
unlist() %>%
tail(., 1) %>%
as.numeric()
for (j in 1:navi.final) { #3. 알아낸 최종번호로 페이지별 정보를 크롤링하기
# 각 페이지에 해당하는 url 생성
url <- paste0(
'https://finance.naver.com/sise/',
'sise_market_sum.nhn?sosok=',i,"&page=",j)
down_table <- GET(url)
Sys.setlocale("LC_ALL", "English")
# 한글 오류 방지를 위해 영어로 로케일 언어 변경
table <- read_html(down_table, encoding = "EUC-KR") %>%
html_table(fill = TRUE)
table <- table[[2]] # 원하는 테이블 추출
Sys.setlocale("LC_ALL", "Korean")
# 한글을 읽기위해 로케일 언어 재변경
table[, ncol(table)] = NULL # 토론식 부분 삭제
table <- na.omit(table) # 빈 행 삭제
# 6자리 티커만 추출
symbol <- read_html(down_table, encoding = "EUC-KR") %>%
html_nodes(., "tbody") %>%
html_nodes(., "td") %>%
html_nodes(., "a") %>%
html_attr(., "href")
symbol <- sapply(symbol, function(x) {
substr(x, nchar(x) - 5, nchar(x))
}) %>% unique() #sapply: 배열데이터 계산
# 테이블에 티커 넣어준 후, 테이블 정리
table$N = symbol
colnames(table)[1] = "종목코드"
rownames(table) = NULL
ticker[[j]] = table #페이지별 테이블을 ticker 리스트에 담아줌
Sys.sleep(0.5) # 페이지 당 0.5초의 슬립 적용
}
# do.call을 통해 리스트를 데이터 프레임으로 묶기
ticker = do.call(rbind, ticker) #4. ticker 리스트에는 개별 cart마다 코스닥 or 코스피 페이지별 테이블이 담겨 있음. 그것을 하나로 합치는 것임
data[[i + 1]] = ticker #5. 첫째 cart에는 코스피 페이지별 테이블이 모두 합쳐진 data.frame이, 두 번째는 코스닥 자료가 들어감
}
# 코스피와 코스닥 테이블 묶기
data <- do.call(rbind, data) #6. 두 data.frame을 묶어줌
assign("ticker_list", data, .GlobalEnv) #7. 최종결과물을 저장함
}
최종적으로 아래와 같은 결과물을 만들 수 있음.
download()
ticker_list %>% head()
## 종목코드 종목명 현재가 전일비 등락률 액면가 시가총액 상장주식수
## 1 005930 삼성전자 44,000 600 +1.38% 100 2,626,704 5,969,783
## 2 000660 SK하이닉스 77,400 4,100 +5.59% 5,000 563,474 728,002
## 3 005935 삼성전자우 36,850 850 +2.36% 100 303,234 822,887
## 4 005380 현대차 128,500 2,000 +1.58% 5,000 274,564 213,668
## 5 035420 NAVER 146,500 1,500 +1.03% 100 241,452 164,813
## 6 012330 현대모비스 248,500 4,500 +1.84% 5,000 236,837 95,307
## 외국인비율 거래량 PER ROE
## 1 57.44 8,784,598 7.30 19.63
## 2 51.60 3,802,918 3.63 38.53
## 3 93.12 1,313,358 6.12 N/A
## 4 44.13 405,745 24.01 2.20
## 5 59.15 370,593 37.21 12.97
## 6 49.26 173,024 12.81 6.30
- 종목코드 검색하기
받아온 ticker_list에서 원하는 기업의 종목코드를 검색할 수 있다.
find_ticker <-
function(name) {
search_result <- ticker_list[grepl(name, ticker_list$종목명, fixed = T), 1:2]
print(search_result)
}
find_ticker("하이닉스")
## 종목코드 종목명
## 2 000660 SK하이닉스
find_ticker("삼성전자")
## 종목코드 종목명
## 1 005930 삼성전자
## 3 005935 삼성전자우
find_ticker("현대")
## 종목코드 종목명
## 4 005380 현대차
## 6 012330 현대모비스
## 43 086280 현대글로비스
## 46 267250 현대중공업지주
## 48 004020 현대제철
## 52 000720 현대건설
## 75 005387 현대차2우B
## 100 017800 현대엘리베이
## 101 001450 현대해상
## 108 005385 현대차우
## 111 069960 현대백화점
## 119 010620 현대미포조선
## 122 294870 HDC현대산업개발
## 128 064350 현대로템
## 149 011210 현대위아
## 154 005440 현대그린푸드
## 155 307950 현대오토에버
## 157 057050 현대홈쇼핑
## 159 011200 현대상선
## 234 267270 현대건설기계
## 242 006390 한일현대시멘트
## 294 126560 현대에이치씨엔
## 365 001500 현대차증권
## 372 079430 현대리바트
## 394 267260 현대일렉트릭
## 402 011760 현대상사
## 485 005389 현대차3우B
## 527 004310 현대약품
## 540 089470 HDC현대EP
## 572 004560 현대비앤지스틸
## 647 227840 현대코퍼레이션홀딩스
## 1148 000725 현대건설우
## 1410 004565 현대비앤지스틸우
## 1425 138540 TIGER 현대차그룹+펀더멘털
## 1621 048410 현대바이오
## 2255 016790 현대사료
## 2333 039010 현대통신
## 2600 170030 현대공업
- 기업명을 통해 보고서 다운로드 받기
제일 처음에 언급했던 것과 마찬가지로, 코드를 실행시키면 자동으로 보고서가 다운로드 받게 만들고 싶다.
아래는 함수의 코드다.
report_down <-
function(name, type = 1, force = F) {
search_result <- ticker_list[grepl(name, ticker_list$종목명, fixed = T), 1:2]
api.key <- '직접 스스로 받은 API키를 치세요'
start.date <- '19990101'
ticker <- search_result[1, 1]
url <- paste0("http://dart.fss.or.kr/api/search.json?auth=",
api.key,"&crp_cd=",ticker,"&start_dt=",start.date,
"&bsn_tp=A00", type)
# auth 발급받은 인증키(40자리)(필수)
# crp_cd 공시대상회사의 종목코드(상장사:숫자 6자리) 또는 고유번호(기타법인:숫자 8자리)
# start_dt 검색시작 접수일자(YYYYMMDD) : 없으면 end_dt
# bsn_tp #A001: 정기 #A002: 반기 #A003: 분기
setwd("자신이 파일을 다운받을 경로를 치세요")
if (nrow(search_result) == 1) {
print(search_result)
#data download
data <- fromJSON(url)
data.df <- data$list
data.df.rcp <- data.df$rcp_no #보고서번호
#Excel download
for (i in 1:10) {
url.business.report = paste0('http://dart.fss.or.kr/dsaf001/main.do?rcpNo=',data.df.rcp[i])
req <- GET(url.business.report)
req <- read_html(req) %>% html_node(xpath = '//*[@id="north"]/div[2]/ul/li[1]/a')
req = req %>% html_attr('onclick')
dcm = stringr::str_split(req, ' ')[[1]][2] %>% readr::parse_number()
query.base = list(
rcp_no = data.df.rcp[i],
dcm_no = dcm,
lang = "ko" #이게 없으면 영문으로 다운로드 됨 (내 경우에만 그럴수도)
)
down.excel = POST('http://dart.fss.or.kr/pdf/download/excel.do',
query = query.base)
writeBin(content(down.excel, "raw"),
paste0(ticker, "_", data.df.rcp[i], '.xls'))
}
} else if (nrow(search_result) == 0) {
print("invalid company name")
} else {
if (force == F) {
print("multiple result: force = T to force downloading")
print(search_result)
} else {
print("multiple result: downloaded forcefully the first company")
print(search_result)
#data download
data <- fromJSON(url)
data.df <- data$list
data.df.rcp <- data.df$rcp_no #보고서번호
#Excel download
for (i in 1:10) {
url.business.report = paste0('http://dart.fss.or.kr/dsaf001/main.do?rcpNo=',data.df.rcp[i])
req <- GET(url.business.report)
req <- read_html(req) %>% html_node(xpath = '//*[@id="north"]/div[2]/ul/li[1]/a')
req = req %>% html_attr('onclick')
dcm = stringr::str_split(req, ' ')[[1]][2] %>% readr::parse_number()
query.base = list(
rcp_no = data.df.rcp[i],
dcm_no = dcm,
lang = "ko" #이게 없으면 영문으로 다운로드 됨 (내 경우에만 그럴수도)
)
down.excel = POST('http://dart.fss.or.kr/pdf/download/excel.do',
query = query.base)
writeBin(content(down.excel, "raw"),
paste0(ticker, "_", data.df.rcp[i], '.xls'))
}
}
}
}
몇 가지 예를 보겠다.
report_down("하이닉스") #정기공시 10건 다운로드
## 종목코드 종목명
## 2 000660 SK하이닉스
report_down("하이닉스", 2) #분기공시 10건 다운로드
## 종목코드 종목명
## 2 000660 SK하이닉스
report_down("현대") #다운로드되지 않음
## [1] "multiple result: force = T to force downloading"
## 종목코드 종목명
## 4 005380 현대차
## 6 012330 현대모비스
## 43 086280 현대글로비스
## 46 267250 현대중공업지주
## 48 004020 현대제철
## 52 000720 현대건설
## 75 005387 현대차2우B
## 100 017800 현대엘리베이
## 101 001450 현대해상
## 108 005385 현대차우
## 111 069960 현대백화점
## 119 010620 현대미포조선
## 122 294870 HDC현대산업개발
## 128 064350 현대로템
## 149 011210 현대위아
## 154 005440 현대그린푸드
## 155 307950 현대오토에버
## 157 057050 현대홈쇼핑
## 159 011200 현대상선
## 234 267270 현대건설기계
## 242 006390 한일현대시멘트
## 294 126560 현대에이치씨엔
## 365 001500 현대차증권
## 372 079430 현대리바트
## 394 267260 현대일렉트릭
## 402 011760 현대상사
## 485 005389 현대차3우B
## 527 004310 현대약품
## 540 089470 HDC현대EP
## 572 004560 현대비앤지스틸
## 647 227840 현대코퍼레이션홀딩스
## 1148 000725 현대건설우
## 1410 004565 현대비앤지스틸우
## 1425 138540 TIGER 현대차그룹+펀더멘털
## 1621 048410 현대바이오
## 2255 016790 현대사료
## 2333 039010 현대통신
## 2600 170030 현대공업
report_down("현대", force=T) #첫번째 종목 다운로드(현대자동차)
## [1] "multiple result: downloaded forcefully the first company"
## 종목코드 종목명
## 4 005380 현대차
## 6 012330 현대모비스
## 43 086280 현대글로비스
## 46 267250 현대중공업지주
## 48 004020 현대제철
## 52 000720 현대건설
## 75 005387 현대차2우B
## 100 017800 현대엘리베이
## 101 001450 현대해상
## 108 005385 현대차우
## 111 069960 현대백화점
## 119 010620 현대미포조선
## 122 294870 HDC현대산업개발
## 128 064350 현대로템
## 149 011210 현대위아
## 154 005440 현대그린푸드
## 155 307950 현대오토에버
## 157 057050 현대홈쇼핑
## 159 011200 현대상선
## 234 267270 현대건설기계
## 242 006390 한일현대시멘트
## 294 126560 현대에이치씨엔
## 365 001500 현대차증권
## 372 079430 현대리바트
## 394 267260 현대일렉트릭
## 402 011760 현대상사
## 485 005389 현대차3우B
## 527 004310 현대약품
## 540 089470 HDC현대EP
## 572 004560 현대비앤지스틸
## 647 227840 현대코퍼레이션홀딩스
## 1148 000725 현대건설우
## 1410 004565 현대비앤지스틸우
## 1425 138540 TIGER 현대차그룹+펀더멘털
## 1621 048410 현대바이오
## 2255 016790 현대사료
## 2333 039010 현대통신
## 2600 170030 현대공업
report_down("횬대") #다운로드되지 않음
## [1] "invalid company name"
- 데이터 읽어오기
Working directory에 파일이 그대로 있다는 것을 가정하면, list.files 함수를 이용해 파일을 가져올 수 있다.
list.files() %>% head() #working directory에 저장된 파일 목록 확인
## [1] "000660_20110829000354.xls" "000660_20111123000206.xls"
## [3] "000660_20120817000001.xls" "000660_20130814001050.xls"
## [5] "000660_20140331002980.xls" "000660_20140814001611.xls"
df <- readxl::read_excel(list.files()[1], sheet = 2) #그 중에서 첫 번째 파일 읽어오기
## New names:
## * `` -> ...2
## * `` -> ...3
df
## # A tibble: 51 x 3
## `연결 재무상태표` ...2 ...3
## <chr> <chr> <chr>
## 1 제 64 기 반기말 2011.06.30 현재 <NA> <NA>
## 2 제 63 기말 2010.12.31 현재 <NA> <NA>
## 3 (단위 : 백만원) <NA> <NA>
## 4 <NA> 제 64 기 반기말 제 63 기말
## 5 자산 <NA> <NA>
## 6 유동자산 5172058 5416086
## 7 현금및현금성자산 747956 1253226
## 8 단기금융상품 1031863 948476
## 9 매출채권 1663852 1604952
## 10 기타수취채권 254822 167684
## # ... with 41 more rows