행위

"주식 재무제표 크롤링"의 두 판 사이의 차이

DB CAFE

1번째 줄: 1번째 줄:
 +
=== R에서 전자공시시스템(DART) API를 이용한 크롤링 ===
 +
 +
# 금융감독원의 전자공시 시스템(http://dart.fss.or.kr/)
 +
# 오픈 API 인증키 신청 필요 , API KEY 발급
 +
# 하루 동안 요청할 수 있는 횟수 10,000 번
 +
# 한번에 최대 10개까지의 데이터 받을수 있음.
 +
# 아무런 쿼리도 입력하지 않으면 단순히 최신 공시 10건을 출력
 +
 +
 +
==== 회사 사업보고서 10건 크롤링 하는 예제 ====
 +
 +
# 해당 주소 http://dart.fss.or.kr/api/search.xml?auth=APIKEY&crp_cd=005930&start_dt=19990101&bsn_tp=A001
 +
# :(A002은 반기, A003은 분기)
 +
# auth 는 발급받은 API key 입력
 +
# crd_cd는 회사의 티커 6자리를 입력
 +
# 데이터를 xml,json 형태( .../api/search. 뒤의 xml을 json으로만 바꾸어주면 됩니다.)
 +
 +
<source lang=r>
 +
library(httr)
 +
library(rvest)
 +
library(jsonlite)
 +
library(XML)
 +
library(methods)
 +
 +
corpCode <- xmlToDataFrame("D:/dev/R/corpCode.xml")
 +
data.df = corpCode$list
 +
 +
 +
api.key = "OPEN API 키값"
 +
#start.date = "19990101"
 +
list_bsns_year <- c('2015', '2016', '2017', '2018', '2019','2020')  #
 +
list_reprt_code <- c('11011', '11012', '11013', '11014') # 분기 리포트
 +
 +
corp_code = "00385363"
 +
#ticker = "005930"
 +
# for(i in 1:6){
 +
#
 +
for(i in list_bsns_year){
 +
  for(j in list_reprt_code){
 +
    url = paste0("https://opendart.fss.or.kr/api/tesstkAcqsDspsSttus.json?crtfc_key=",api.key,"&corp_code=",corp_code,"&bsns_year=",list_bsns_year[i],"&reprt_code=",list_reprt_code[j])
 +
    # print(url)
 +
    data = fromJSON(url)
 +
    # data.df = data$list
 +
    data.df <- rbind(data.df,data$list)   
 +
    # data.df.rcept_no = data.df$rcept_no
 +
    # data.df %>% head()
 +
  }
 +
}
 +
 +
# data.df %>% head()
 +
</source>
 +
 +
==== 공시번호로 사업보고서 확인 ====
 +
# 필요한 값은 공시번호에 해당하는 rcp_no 값 (data.df$rcept_no) 만 data.df.rcp 변수에 저장
 +
# dart 홈페이지 공시들의 url 파악  필요
 +
# 정기공시를 검색해보면 00 년 사업보고서 예시
 +
#: url 주소
 +
#: http://dart.fss.or.kr/dsaf001/main.do?rcpNo=20160330000776
 +
 +
==== 재무제표 파일 다운로드 ====
 +
 +
# 첨부되어 있는 재무제표 파일들을 다운로드 받기 위한 각 공시별 dcm 구하기
 +
# dcm을 뽑아내기 위해  크롬 > 개발자도구 >  xpath를 이용하여 추출
 +
#: //*[@id="north"]/div[2]/ul/li[1]/a
 +
# 해당 부분의 값을 R에서 추출하는 법
 +
<source lang=r>
 +
# 위 페이지 url 정보를 GET() 함수를 통해 가져오며,read_html()을 통해 html 정보를 읽을 후,xpath 값으로 해당 노드의 정보를 읽어오도록 합니다.
 +
url.business.report = 'http://dart.fss.or.kr/dsaf001/main.do?rcpNo=20180402005019' 
 +
req = GET(url.business.report)
 +
req = read_html(req) %>% html_node(xpath = '//*[@id="north"]/div[2]/ul/li[1]/a')
 +
</source>
 +
req
 +
{xml_node}
 +
"#download"
 +
 +
onclick="openPdfDownload('20180402005019', '6060273'); return false;"> [1] "/images/common/viewer_down.gif" style="cursor:pointer;" alt="다운로드" title="다운로드">
 +
 +
req 변수 확인해보면 onclick 뒤의 openPdfDownload 부분이 있으며 앞의 20180402005019 부분은 위에서 나온 rcp_no,위의 6060273 부분이 해당 파일의 dcm에 해당.
 +
 +
dcm은 각 공시에 해당하는 문서번호로 이해.
 +
 +
<source lang=r>
 +
req = req %>% html_attr('onclick')
 +
dcm = stringr::str_split(req, ' ')[[1]][2] %>% readr::parse_number()
 +
</source>
 +
 +
# html_attr() 함수를 이용해 'onclick' 부분의 데이터만 뽑아
 +
# stringr 패키지의 str_split() 함수를 통해 캐릭터 값을 나눠준 후 두번째 값만을 뽑아내기
 +
# 마지막으로 readr 패키지의 parse_number() 함수를 통해 해당 값에서 숫자 값만을 뽑아주도록 합니다.
 +
# 정규표현식을 아신다면 해당작업이 훨씬 쉽게 가능
 +
 +
===== 홈페이지 첨부된 엑셀 파일이 다운로드 =====
 +
# 상단의 다운로드 부분을 클릭한 후 팝업창이 뜨면, 다시 개발자 도구를 열어줍니다.
 +
# 재무제표 항목을 클릭하면 파일이 다운로드
 +
 +
http://dart.fss.or.kr/pdf/download/excel.do
 +
 +
위의 url에 데이터를 요청하며 쿼리에 해당하는 부분은 rcp_no는 위에서 구한 값(공시번호),dcm_no 역시 위에서 찾아낸 문서번호,lang은 한국어인 ko가 있습니다.
 +
 +
 +
R에서 post 형식으로 나타내면 다음과 같습니다.
 +
<source lang=r>
 +
query.base = list(
 +
    rcp_no = '20180402005019',
 +
    dcm_no = dcm
 +
  )
 +
 
 +
down.excel = POST('http://dart.fss.or.kr/pdf/download/excel.do', query = query.base)
 +
down.excel
 +
Response [http://dart.fss.or.kr/pdf/download/excel.do?rcp_no=20180402005019&dcm_no=5026126]
 +
  Date: 2019-02-18 14:08
 +
  Status: 200
 +
  Content-Type: application/vnd.ms-excel
 +
  Size: 74.8 kB
 +
 +
down.excel 변수를 확인해보면 엑셀 파일이 연결되어 있음이 확인됩니다.
 +
 +
writeBin(content(down.excel, "raw"), paste0(ticker, "_", data.df.rcp[i], '.xls'))
 +
writeBin() 함수를 통해 해당 파일을 다운로드 받으며 저장 이름은 티커_rcp.xls 로 하도록 합니다.
 +
 +
모든 재무제표 항목이 포함된 엑셀파일이 잘 다운로드 됨이 확인됩니다.
 +
 +
df = readxl::read_excel( paste0(ticker, "_", data.df.rcp[i], '.xls'), sheet = 2)
 +
df
 +
# A tibble: 62 x 4
 +
  `연결 재무상태표`        ..2      ..3      ..4     
 +
  <chr>                    <chr>    <chr>    <chr>   
 +
1 제 49 기 2017.12.31 현재 NA        NA        NA     
 +
2 제 48 기 2016.12.31 현재 NA        NA        NA     
 +
3 제 47 기 2015.12.31 현재 NA        NA        NA     
 +
4 (단위 : 백만원)          NA        NA        NA     
 +
5 NA                      제 49 기  제 48 기  제 47 기
 +
6 자산                    NA        NA        NA     
 +
7 유동자산                146982464 141429704 124814725
 +
8 현금및현금성자산        30545130  32111442  22636744
 +
9 단기금융상품            49447696  52432411  44228800
 +
10 단기매도가능금융자산    3191375  3638460  4627530 
 +
# ... with 52 more rows
 +
 +
 +
read_excel() 함수를 통해 다운로드 받은 파일을읽어올 수도 있습니다.
 +
 +
 +
처음 API를 통한 json 형태로 얻은 10개의 rcp를 통해 최근 10년치 엑셀 파일을 모두 다운로드 받는 방법은 for loop를 통해 해결할 수 있습니다.
 +
 +
<source lang=r>
 +
for (i in 1 : length(data.df.rcp)) {
 +
 +
  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 = '20180402005019',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')) 
 +
  Sys.sleep(2) 
 +
  print(i) 
 +
}
 +
</source>
 +
 +
 +
 +
 +
=== 네이버 증권 재무제표 ===
 
https://engkimbs.tistory.com/625
 
https://engkimbs.tistory.com/625
  

2020년 12월 15일 (화) 16:33 판

thumb_up 추천메뉴 바로가기


1 R에서 전자공시시스템(DART) API를 이용한 크롤링[편집]

  1. 금융감독원의 전자공시 시스템(http://dart.fss.or.kr/)
  2. 오픈 API 인증키 신청 필요 , API KEY 발급
  3. 하루 동안 요청할 수 있는 횟수 10,000 번
  4. 한번에 최대 10개까지의 데이터 받을수 있음.
  5. 아무런 쿼리도 입력하지 않으면 단순히 최신 공시 10건을 출력


1.1 회사 사업보고서 10건 크롤링 하는 예제[편집]

  1. 해당 주소 http://dart.fss.or.kr/api/search.xml?auth=APIKEY&crp_cd=005930&start_dt=19990101&bsn_tp=A001
  2.  :(A002은 반기, A003은 분기)
  3. auth 는 발급받은 API key 입력
  4. crd_cd는 회사의 티커 6자리를 입력
  5. 데이터를 xml,json 형태( .../api/search. 뒤의 xml을 json으로만 바꾸어주면 됩니다.)
library(httr)
library(rvest)
library(jsonlite)
library(XML)
library(methods)

corpCode <- xmlToDataFrame("D:/dev/R/corpCode.xml")
data.df = corpCode$list


api.key = "OPEN API 키값"
#start.date = "19990101"
list_bsns_year <- c('2015', '2016', '2017', '2018', '2019','2020')  # 
list_reprt_code <- c('11011', '11012', '11013', '11014') # 분기 리포트

corp_code = "00385363"
#ticker = "005930"
# for(i in 1:6){
# 
for(i in list_bsns_year){
  for(j in list_reprt_code){
    url = paste0("https://opendart.fss.or.kr/api/tesstkAcqsDspsSttus.json?crtfc_key=",api.key,"&corp_code=",corp_code,"&bsns_year=",list_bsns_year[i],"&reprt_code=",list_reprt_code[j])
    # print(url)
    data = fromJSON(url)
    # data.df = data$list
    data.df <- rbind(data.df,data$list)    
    # data.df.rcept_no = data.df$rcept_no
    # data.df %>% head()
  }
}

# data.df %>% head()

1.2 공시번호로 사업보고서 확인[편집]

  1. 필요한 값은 공시번호에 해당하는 rcp_no 값 (data.df$rcept_no) 만 data.df.rcp 변수에 저장
  2. dart 홈페이지 공시들의 url 파악 필요
  3. 정기공시를 검색해보면 00 년 사업보고서 예시
    url 주소
    http://dart.fss.or.kr/dsaf001/main.do?rcpNo=20160330000776

1.3 재무제표 파일 다운로드[편집]

  1. 첨부되어 있는 재무제표 파일들을 다운로드 받기 위한 각 공시별 dcm 구하기
  2. dcm을 뽑아내기 위해 크롬 > 개발자도구 > xpath를 이용하여 추출
    //*[@id="north"]/div[2]/ul/li[1]/a
  3. 해당 부분의 값을 R에서 추출하는 법
# 위 페이지 url 정보를 GET() 함수를 통해 가져오며,read_html()을 통해 html 정보를 읽을 후,xpath 값으로 해당 노드의 정보를 읽어오도록 합니다.
url.business.report = 'http://dart.fss.or.kr/dsaf001/main.do?rcpNo=20180402005019'  
req = GET(url.business.report) 
req = read_html(req) %>% html_node(xpath = '//*[@id="north"]/div[2]/ul/li[1]/a')

req {xml_node} "#download"

onclick="openPdfDownload('20180402005019', '6060273'); return false;"> [1] "/images/common/viewer_down.gif" style="cursor:pointer;" alt="다운로드" title="다운로드">

req 변수 확인해보면 onclick 뒤의 openPdfDownload 부분이 있으며 앞의 20180402005019 부분은 위에서 나온 rcp_no,위의 6060273 부분이 해당 파일의 dcm에 해당.

dcm은 각 공시에 해당하는 문서번호로 이해.

req = req %>% html_attr('onclick')
dcm = stringr::str_split(req, ' ')[[1]][2] %>% readr::parse_number()
  1. html_attr() 함수를 이용해 'onclick' 부분의 데이터만 뽑아
  2. stringr 패키지의 str_split() 함수를 통해 캐릭터 값을 나눠준 후 두번째 값만을 뽑아내기
  3. 마지막으로 readr 패키지의 parse_number() 함수를 통해 해당 값에서 숫자 값만을 뽑아주도록 합니다.
  4. 정규표현식을 아신다면 해당작업이 훨씬 쉽게 가능
1.3.1 홈페이지 첨부된 엑셀 파일이 다운로드[편집]
  1. 상단의 다운로드 부분을 클릭한 후 팝업창이 뜨면, 다시 개발자 도구를 열어줍니다.
  2. 재무제표 항목을 클릭하면 파일이 다운로드

http://dart.fss.or.kr/pdf/download/excel.do

위의 url에 데이터를 요청하며 쿼리에 해당하는 부분은 rcp_no는 위에서 구한 값(공시번호),dcm_no 역시 위에서 찾아낸 문서번호,lang은 한국어인 ko가 있습니다.


R에서 post 형식으로 나타내면 다음과 같습니다.

query.base = list(
    rcp_no = '20180402005019',
    dcm_no = dcm
  )
  
down.excel = POST('http://dart.fss.or.kr/pdf/download/excel.do', query = query.base)
down.excel
Response [http://dart.fss.or.kr/pdf/download/excel.do?rcp_no=20180402005019&dcm_no=5026126]
  Date: 2019-02-18 14:08
  Status: 200
  Content-Type: application/vnd.ms-excel
  Size: 74.8 kB

down.excel 변수를 확인해보면 엑셀 파일이 연결되어 있음이 확인됩니다.

writeBin(content(down.excel, "raw"), paste0(ticker, "_", data.df.rcp[i], '.xls'))
writeBin() 함수를 통해 해당 파일을 다운로드 받으며 저장 이름은 티커_rcp.xls 로 하도록 합니다.

모든 재무제표 항목이 포함된 엑셀파일이 잘 다운로드 됨이 확인됩니다.

df = readxl::read_excel( paste0(ticker, "_", data.df.rcp[i], '.xls'), sheet = 2)
df
# A tibble: 62 x 4
   `연결 재무상태표`        ..2       ..3       ..4      
   <chr>                    <chr>     <chr>     <chr>    
 1 제 49 기 2017.12.31 현재 NA        NA        NA       
 2 제 48 기 2016.12.31 현재 NA        NA        NA       
 3 제 47 기 2015.12.31 현재 NA        NA        NA       
 4 (단위 : 백만원)          NA        NA        NA       
 5 NA                       제 49 기  제 48 기  제 47 기 
 6 자산                     NA        NA        NA       
 7 유동자산                 146982464 141429704 124814725
 8 현금및현금성자산         30545130  32111442  22636744 
 9 단기금융상품             49447696  52432411  44228800 
10 단기매도가능금융자산     3191375   3638460   4627530  
# ... with 52 more rows


read_excel() 함수를 통해 다운로드 받은 파일을읽어올 수도 있습니다.


처음 API를 통한 json 형태로 얻은 10개의 rcp를 통해 최근 10년치 엑셀 파일을 모두 다운로드 받는 방법은 for loop를 통해 해결할 수 있습니다.

<source lang=r>
for (i in 1 : length(data.df.rcp)) {

  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 = '20180402005019',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'))  
  Sys.sleep(2)  
  print(i)  
}



2 네이버 증권 재무제표[편집]

https://engkimbs.tistory.com/625

import requests
from bs4 import BeautifulSoup

URL = "https://finance.naver.com/item/main.nhn?code=005930"

samsung_electronic = requests.get(URL)
html = samsung_electronic.text

soup = BeautifulSoup(html, 'html.parser')

finance_html = soup.select('div.section.cop_analysis div.sub_section')[0]

th_data = [item.get_text().strip() for item in finance_html.select('thead th')]
annual_date = th_data[3:7]
quarter_date = th_data[7:13]

finance_index = [item.get_text().strip() for item in finance_html.select('th.h_th2')][3:]

finance_data = [item.get_text().strip() for item in finance_html.select('td')]

import numpy as np

finance_data = np.array(finance_data)
finance_data.resize(len(finance_index), 10)

finance_date = annual_date + quarter_date

import pandas as pd
finance = pd.DataFrame(data=finance_data[0:,0:], index=finance_index, columns=finance_date)

annual_finance = finance.iloc[:, :4]
quarter_finance = finance.iloc[:, 4:]