출처:
퀀트투자쿡북 / 저자: 이현열: 5.1 한국거래소의 산업별 현황 및 개별지표 크롤링
(혼자한 연습)
library(rvest)
library(httr)
library(tidyverse) #dplyr을 받아야 %>%(pipeline)을 사용할 수 있음
아래의 주소에서 산업별 지표를 크롤링하고 싶다고 하자.
산업별지표: http://marketdata.krx.co.kr/mdi#document=03030103
그런데 들어가보면, 이미 엑셀로 다운로드 받을 수 있는 걸 확인할 수 있다. 그러나 매번 홈페이지에 들어가 엑셀을 클릭하고 다운받아 다시 R에 올리는 것은 상당히 비효율적이다. 처음에 조금 시간을 들여서 코드를 짜면, 이를 이용해서 그때그때 곧바로 엑셀형 데이터를 csv로 받아 R까지 올리는 작업을 자동화할 수 있다.
홈페이지에 들어가 엑셀버튼을 누르면 두 가지 일이 벌어진다. (개발자모드 Network 탭에서 확인 가능)
1. GenerateOTP.jspx에서 OTP를 생성 2. download.jspx에서 OTP를 제출하고 자료를 받음
따라서 우리는 이 두 과정을 코드로 그대로 재현시켜야 한다.
gen_otp_url <- "http://marketdata.krx.co.kr/contents/COM/GenerateOTP.jspx"
gen_otp_data <-
list(
name = "fileDown",
filetype = "csv", #to save memory
url = "MKD/03/0303/03030103/mkd03030103",
tp_cd = "ALL",
date = "20190809",
lang = "ko",
pagePath = "/contents/MKD/03/0303/03030103/MKD03030103.jsp"
)
otp <-
POST(
gen_otp_url,
query = gen_otp_data
) %>%
read_html() %>%
html_text
큰 틀에서 url을 요청해 전체 다운로드 후, html을 읽어내는 것은 동일.
이번에 다른 점은 query argument가 들어간다는 것. → 즉 otp 생성 시에는 쿼리 argument를 별도로 넣어줘야 함.
down_url = 'http://file.krx.co.kr/download.jspx'
down_sector = POST(down_url, query = list(code = otp),
add_headers(referer = gen_otp_url)) %>%
read_html() %>%
html_text() %>%
read_csv()
down_sector %>% head()
## # A tibble: 6 x 7
## 시장구분 종목코드 종목명 산업분류 `현재가(종가)` 전일대비 `시가총액(원)`
## <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 코스피 030720 동원수산~ 어업 9300 460 43280386500
## 2 코스피 007160 사조산업~ 어업 44650 1200 223250000000
## 3 코스피 006040 동원산업~ 어업 226000 -5500 831146866000
## 4 코스피 004970 신라교역~ 어업 12450 0 199200000000
## 5 코스피 012320 경동인베스트~ 광업 32350 350 76508494050
## 6 코스피 003580 넥스트사이언~ 광업 3105 -30 72907384095
otp 생성시와 마찬가지로 query argument가 들어가는데, 여기서 추가적으로 리스트 내 코드 구문이 들어간다. 여기서 otp를 제출한다.
ifelse(dir.exists('data'), FALSE, dir.create('data'))
## [1] FALSE
write.csv(down_sector, 'data/krx_sector.csv')
똑같은 과정을 거친다.
gen_otp_url <-
'http://marketdata.krx.co.kr/contents/COM/GenerateOTP.jspx'
gen_otp_data <-
list(
name = 'fileDown',
filetype = 'csv',
url = "MKD/13/1302/13020401/mkd13020401",
market_gubun = 'ALL',
gubun = '1',
schdate = '20190607',
pagePath = "/contents/MKD/13/1302/13020401/MKD13020401.jsp")
otp <-
POST(gen_otp_url,
query = gen_otp_data) %>%
read_html() %>%
html_text()
down_url <- 'http://file.krx.co.kr/download.jspx'
down_ind <-
POST(down_url,
query = list(code = otp),
add_headers(referer = gen_otp_url)) %>%
read_html() %>%
html_text() %>%
read_csv()
print(down_ind)
## # A tibble: 2,204 x 13
## 일자 종목코드 종목명 관리여부 종가 EPS PER BPS PBR
## <date> <chr> <chr> <chr> <dbl> <chr> <chr> <chr> <chr>
## 1 2019-06-07 000250 삼천당제약~ - 39650 409 96.94 6,719 5.9
## 2 2019-06-07 000440 중앙에너비~ - 6880 958 7.18 7,269 0.95
## 3 2019-06-07 001000 신라섬유~ - 2225 7 317.~ 587 3.79
## 4 2019-06-07 001540 안국약품~ - 11350 1,154 9.84 11,2~ 1.01
## 5 2019-06-07 001810 무림SP - 2795 505 5.53 9,212 0.3
## 6 2019-06-07 001840 이화공영~ - 5290 24 220.~ 2,164 2.44
## 7 2019-06-07 002230 피에스텍~ - 4275 - - 7,283 0.59
## 8 2019-06-07 002290 삼일기업공~ - 3185 250 12.74 4,578 0.7
## 9 2019-06-07 002680 한탑 - 2435 - - 2,135 1.14
## 10 2019-06-07 002800 신신제약~ - 7050 191 36.91 3,595 1.96
## # ... with 2,194 more rows, and 4 more variables: 주당배당금 <dbl>,
## # 배당수익률 <dbl>, `게시물 일련번호` <dbl>, 총카운트 <dbl>
write.csv(down_ind, 'data/krx_ind.csv')
매번 위의 코드를 돌릴때마다 날짜 부분을 수정해주는 것도 힘들다.
따라서 영업일 부분 또한 자동화를 시킬 수 있다.
그러려면 우선 영업일 정보를 가져올 수 있어야 한다.
네이버 금융에서 가져오도록 하되, 이번에는 전체 페이지를 받고, html을 읽고 분해해서 찾아내기보다, Xpath라는 부분으로 가져오도록 한다.
url <- 'https://finance.naver.com/sise/sise_deposit.nhn'
biz_day <- GET(url) %>%
read_html(encoding = 'EUC-KR') %>%
html_nodes(xpath =
'//*[@id="type_1"]/div/ul[2]/li/span') %>%
html_text() %>%
str_match(('[0-9]+.[0-9]+.[0-9]+') ) %>%
str_replace_all('\\.', '')
print(biz_day)
## [1] "20190807"
1, 2에서 본 코드에서 date 부분을 최근 영업일로 바꿔주기만 하면 된다.
# 최근 영업일 구하기
url = 'https://finance.naver.com/sise/sise_deposit.nhn'
biz_day = GET(url) %>%
read_html(encoding = 'EUC-KR') %>%
html_nodes(xpath =
'//*[@id="type_1"]/div/ul[2]/li/span') %>%
html_text() %>%
str_match(('[0-9]+.[0-9]+.[0-9]+') ) %>%
str_replace_all('\\.', '')
# 산업별 현황 OTP 발급
gen_otp_url =
'http://marketdata.krx.co.kr/contents/COM/GenerateOTP.jspx'
gen_otp_data = list(
name = 'fileDown',
filetype = 'csv',
url = 'MKD/03/0303/03030103/mkd03030103',
tp_cd = 'ALL',
date = biz_day, # 최근영업일로 변경
lang = 'ko',
pagePath = '/contents/MKD/03/0303/03030103/MKD03030103.jsp')
otp = POST(gen_otp_url, query = gen_otp_data) %>%
read_html() %>%
html_text()
# 산업별 현황 데이터 다운로드
down_url = 'http://file.krx.co.kr/download.jspx'
down_sector = POST(down_url, query = list(code = otp),
add_headers(referer = gen_otp_url)) %>%
read_html() %>%
html_text() %>%
read_csv()
#ifelse(dir.exists('data'), FALSE, dir.create('data'))
write.csv(down_sector, 'data/krx_sector.csv')
# 개별종목 지표 OTP 발급
gen_otp_url =
'http://marketdata.krx.co.kr/contents/COM/GenerateOTP.jspx'
gen_otp_data = list(
name = 'fileDown',
filetype = 'csv',
url = "MKD/13/1302/13020401/mkd13020401",
market_gubun = 'ALL',
gubun = '1',
schdate = biz_day, # 최근영업일로 변경
pagePath = "/contents/MKD/13/1302/13020401/MKD13020401.jsp")
otp = POST(gen_otp_url, query = gen_otp_data) %>%
read_html() %>%
html_text()
# 개별종목 지표 데이터 다운로드
down_url = 'http://file.krx.co.kr/download.jspx'
down_ind = POST(down_url, query = list(code = otp),
add_headers(referer = gen_otp_url)) %>%
read_html() %>%
html_text() %>%
read_csv()
write.csv(down_ind, 'data/krx_ind.csv')
데이터 정리 부분은 나중에 직접 해보도록 한다.