본문 바로가기
데이터 분석/데이터 분석

파이썬으로 코스피 코스닥 상장기업 재무정보 크롤링하기

by thomasito 2022. 1. 23.
반응형

코스피 코스닥 상장기업 추정배당금

2022.01.18 - [투자/배당주투자] - 2022년 예상 배당금 (코스피, 코스닥 전체 종목)

 

표준화된 재무정보 구하기

  최근에 dart_fss 모듈을 사용해서 금융감독원 DART 전자공시시스템의 OPEN API를 활용하여 크롤링하는 작업을 시도해보았다. 데이터로 활용하기 어려운 부분은 표준화가 되어 있지 않다는 점이다. (회사마다 특성이 다르니까 재무제표 항목도 약간씩 다르다.) 그래서 어떻게 하면 표준화된 재무정보를 얻을 수 있는지 찾아보다가 어떤 능력자 분께서 FNguide를 아주 간단한 코드로 크롤링하시는 것을 참고할 수 있었다. 

 

https://wikidocs.net/6660

 

2) 웹 페이지 크롤링

이번 절에서는 웹 페이지의 데이터 중에서 원하는 값만 가져오는 스크레이핑에 대해 간략하게 알아보 겠습니다. 스크레이핑은 웹에서 HTML 파일을 다운로드하는 과정과 다운로드한 ...

wikidocs.net

 

에스피지(058610) 재무정보 & 주당배당금 구하기

  파이썬 알고리즘 트레이딩 저자분께서 짜놓은 코드를 참고하여 재무정보를 크롤링하는 함수는 아래와 같다.

# =============================================================================
# 코스피 종목 재무제표 가져오기 =================================================
# =============================================================================

def FS_crawler(code):
    
    re_enc = re.compile("encparam: '(.*)'", re.IGNORECASE) 
    re_id = re.compile("id: '([a-zA-Z0-9]*)' ?", re.IGNORECASE)
    
    url = "http://companyinfo.stock.naver.com/v1/company/c1010001.aspx?cmp_cd={}".format(code) 
    html = requests.get(url).text 
    encparam = re_enc.search(html).group(1) 
    encid = re_id.search(html).group(1)
    
    url = "http://companyinfo.stock.naver.com/v1/company/ajax/cF1001.aspx?cmp_cd={}&fin_typ=0&freq_typ=A&encparam={}&id={}".format(code, encparam, encid) 
    headers = {"Referer": "HACK"}
    html = requests.get(url, headers=headers).text 
    # print(html)
    
    dfs = pd.read_html(html)
    df = dfs[1]['연간연간컨센서스보기']
    df.index = dfs[1]['주요재무정보'].values.flatten()
    
    return df

 

 이 함수에 현재 내가 보유하고 있는 종목 중 비중이 가장 큰 에스피지의 종목코드인 058610을 넣어서 df 변수에 넣어준 후 엑셀로 만들어 어떤 형태로 추출되는지 확인해 보겠다. 

df = FS_crawler("058610")
# 에스피지 종목코드 058610

df.to_excel("에스피지재무정보.xlsx")

이렇게 이쁘게 데이터프레임으로 만들어진다.

 현금 DPS는 주당 지급한 연간 배당액을 의미한다. (저 숫자는 연간 배당금액 기준이며, 연간 배당을 2번이나 4번 지급할 수도 있으니까 올해 3월에 지급하는 금액이라고 보면 안 된다.) 2021/12(E)는 애널리스트들이 추정한 숫자를 말하며 2022년 3월에 에스피지가 지급할 것으로 예상되는 배당금은 250원으로 작년보다 60% 넘게 배당금이 증액될 것으로 예상된다. 에스피지는 연 1회 배당을 지급하므로 3월에 지급하는 배당금일 것으로 추론된다.

 

 2020년 EPS, 2020년 DPS, 2021년 예상 EPS, 2021년 예상 DPS만 추출하는 함수는 아래와 같다.

# =============================================================================
# 코스피 200종목 DPS 추정치 그대로 가져오기 =====================================
# =============================================================================

def DPS_crawler(code):
    
    # code="006800"
    re_enc = re.compile("encparam: '(.*)'", re.IGNORECASE) 
    re_id = re.compile("id: '([a-zA-Z0-9]*)' ?", re.IGNORECASE)
    
    url = "http://companyinfo.stock.naver.com/v1/company/c1010001.aspx?cmp_cd={}".format(code) 
    html = requests.get(url).text 
    encparam = re_enc.search(html).group(1) 
    encid = re_id.search(html).group(1)
    
    url = "http://companyinfo.stock.naver.com/v1/company/ajax/cF1001.aspx?cmp_cd={}&fin_typ=0&freq_typ=A&encparam={}&id={}".format(code, encparam, encid) 
    headers = {"Referer": "HACK"}
    html = requests.get(url, headers=headers).text 
    # print(html)
    
    import  pandas  as  pd
    
    dfs = pd.read_html(html)
    df = dfs[1]['연간연간컨센서스보기']
    df.index = dfs[1]['주요재무정보'].values.flatten()
    
    EPS_forecast = df.loc['EPS(원)'].loc['2021/12(E)  (IFRS연결)']
    DPS_forecast =  df.loc['현금DPS(원)'].loc['2021/12(E)  (IFRS연결)']
     
    EPS_2020 = df.loc['EPS(원)'].loc['2020/12  (IFRS연결)']
    DPS_2020 = df.loc['현금DPS(원)'].loc['2020/12  (IFRS연결)']
    
    EPS_2020 = round(EPS_2020)
    DPS_2020 = round(DPS_2020)
    EPS_forecast = round(EPS_forecast)
    DPS_forecast = round(DPS_forecast)
    
    print("2021년 EPS ", EPS_2020)
    print("2021년 DPS :", DPS_2020)
    print("2022년 추정 EPS :", EPS_forecast)
    print("2022년 추정 DPS :", DPS_forecast)
    
    return EPS_2020, DPS_2020, EPS_forecast, DPS_forecast

 

 

전체종목 재무정보 & 주당배당금 구하기

 현금 DPS는 주당 지급한 연간 배당액을 의미한다. (저 숫자는 연간 배당금액 기준이며, 연간 배당을 2번이나 4번 지급할 수도 있으니까 올해 3월에 지급하는 금액이라고 보면 안 된다.) 2021/12(E)는 애널리스트들이 추정한 숫자를 말하며 2022년 3월에 에스피지가 지급할 것으로 예상되는 배당금은 250원으로 작년보다 60% 상향된 수준일 것으로 예상된다. 코스피 전종목에 대해서 주당배당금 추정치를 크롤링하려면 어떻게 해야 할까?

 

 다행히 FinanceDataReader 라는 모듈을 통해 한국 거래소 상장 종목 전체종목을 가져올 수 있다. 위에서 만든 FS_crawler 함수에는 '종목코드'만 넣기 때문에, 종목코드(krx_code)와 종목명(krx_name)을 분류한다. 아래와 같이 종목코드와 종목명이 잘 출력 된다.

import FinanceDataReader as fdr

# 한국거래소 상장종목 전체
df_krx = fdr.StockListing('KRX')
df_krx.head()

krx_code = df_krx['Symbol'].to_list()
krx_name = df_krx['Name'].to_list()

print(krx_code[:5],krx_name[:5])

 다음으로는 종목코드를 for 문으로 넣으며 2022년에 받을 추정 배당금을 크롤링해보자. 애널리스트가 추정치를 발표하지 않은 종목의 경우 추정치 부분의 데이터가 없으므로 오류가 발생할 것이다. 따라서 우선 df_resultt 라는 데이터프레임 변수를 만들고 try: 문으로 추정치가 있는 정보를 크롤링하고, except: 문으로 추정치가 없어 오류가 발생하는 것들은 pass 처리한다. 마지막으로 컬럼에는 컬럼명들을 잘 넣어준 후 엑셀로 출력한다.

import pandas as pd

df_resultt = pd.DataFrame()

for i in range(len(krx_code)):
    
    try:
    
        print(krx_code[i], krx_name[i])
        result = DPS_crawler(krx_code[i])
        print(result)
        s = pd.Series(result, name = krx_name[i])
        df_resultt = df_resultt.append(s, ignore_index=False)
        # df_result.set_index(stock_list[i][1])
        
    except:
        
        print("실패",krx_code[i], krx_name[i])
        pass


df_resultt.columns = ["2021년 주당순이익","2021년 배당금","2022년 추정 주당순이익","2022년 추정 배당금"]
df_resultt.to_excel("2021년예상배당금목록t.xlsx")

 

 krx_code 에 변수가 약 7200개가 되고 개별종목이 아닌 ETF 도 포함되어 있기 때문에 예외처리로 나가는 부분들이 꽤 많다. 최종적으로 추정 배당금이 크롤링된 종목은 498개이다. 결과는 아래 링크를 확인하면 된다.

https://investraveler.tistory.com/222

 

2022년 예상 배당금 (코스피, 코스닥 전체 종목)

2022년 예상 배당금 목록 코스피, 코스닥 전체 종목 2022년 추정 배당금 (출처 : fn guide) 종목명은 ABC, 가나다 순서로 되어 있으며 검색하고자 하는 종목을 Ctrl + F 버튼을 누르고 찾아주세요 ^^ (검

investraveler.tistory.com

 

 참고로 코스피 상위 200 종목에 대한 크롤링을 돌리려면 아래 코드를 참고하면 된다.

# 코스피 200 종목 가져오기

from bs4 import BeautifulSoup
import csv
import os
import re
import requests

stock_list = []
BaseUrl = 'http://finance.naver.com/sise/entryJongmok.nhn?&page='

for i in range(1, 21):
    url = BaseUrl + str(i)
    r = requests.get(url)
    soup = BeautifulSoup(r.text, 'lxml')
    items = soup.find_all('td', {'class': 'ctg'})

    for item in items:
        #print(item)
        txt = item.a.get('href') # https://finance.naver.com/item/main.nhn?code=006390
        k = re.search('[\d]+', txt) ##정규표현식 사용. [\d] 숫자표현, + : 반복
        # print(k)
        if k:
            code = k.group()
            name = item.text
            data = code, name
            stock_list.append(data)
            print(data)

            with open ('KOSPI200.csv', 'a', newline='') as f: ## with 블록안에서 open, 블록밖에서 자동으로 close.
                writer = csv.writer(f)
                writer.writerow(data)

# 코스피 상위 200 종목 이름 가져오기
stock_name = []            
for i in range(len(stock_list)):
    print(stock_list[i][1])
    stock_name.append(stock_list[i][1])
    
stock_code = []
for i in range(len(stock_list)):
    print(stock_list[i][0])
    stock_code.append(stock_list[i][0])
    
print(stock_code)
반응형

댓글