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

파이썬 퀀트투자(5): WICS 기준 섹터정보 크롤링, 적재

by 코듀킹 2024. 10. 12.

일반적으로 주식의 섹터를 나누는 기준은 MSCI와 S&P가 개발한 GICS를 가장 많이 사용합니다. 국내 종목의 GICS 기준 정보 역시 한국거래소에서 제공하고 있으나, 이는 독점적 지적재산으로 명시했기에 사용하는데 무리가 있습니다. 그러나 지수제공업체인 FnGuide Index에서는 GICS와 비슷한 WICS 산업분류를 발표하고 있습니다. 그래서 WICS를 크롤링하여 필요한 정보를 수집해보겠습니다.

 

 

1. wiseindex 사이트에서 섹터 정보 크롤링

http://www.wiseindex.com/Index 

먼저 웹페이지에 접속해 왼쪽에서 [WISE SECTOR INDEX → WICS → 에너지]를 클릭합니다. 그 후 [Components] 탭을 클릭하면 해당 섹터의 구성종목을 확인할 수 있습니다.

 

 

크롤링을 하기 앞서 개발자도구 화면을 통해 해당 페이지의 데이터전송 과정을 살펴보겠습니다. 일자를 선택하면 [Network] 탭의 'GetIndexComponets' 항목에 데이터 전송 과정이 나타납니다. 

 

 

Request URL은 데이터를 가져오는 주소입니다. 이 주소로 접속해보면, json형태로 데이터가 담긴 화면을 볼 수 있습니다. 이 URL을 분석하면 다음과 같습니다. 

https://www.wiseindex.com/Index/GetIndexComponets?ceil_yn=0&dt=20241011&sec_cd=G10

  1. http://www.wiseindex.com/Index/GetIndexComponets: 데이터를 요청하는 url입니다.
  2. ceil_yn = 0: 실링 여부를 나타내며, 0은 비실링을 의미합니다.
  3. dt=20241011: 조회일자를 나타냅니다.
  4. sec_cd=G10: 섹터 코드를 나타냅니다.

 

Request URL은 아래와 같이 json형식의 데이터로 구성되어있습니다. 파이썬의 json 패키지를 활용하면 이를 매우 간단하고 빠른속도로 데이터를 받아올 수 있습니다.

 

dt부분만 미리 수집해놓은 biz_day로 설정을 해주고, get() 함수를 통해 페이지의 내용을 받아오며, json() 메서드를 통해 위 데이터를 그대로 받아올 수 있습니다.

 

import json
import requests as rq
import pandas as pd

url = f'''http://www.wiseindex.com/Index/GetIndexComponets?ceil_yn=0&dt={biz_day}&sec_cd=G10'''
data = rq.get(url).json()

type(data) #dict

 

파이썬에서는 json 데이터가 딕셔너리 형태로 변경되는데, 어떠한 키가 있는지 확인해보겠습니다.

print(data.keys())
# 결과 : dict_keys(['info', 'list', 'sector', 'size'])

 

각각의 키에 어떤 정보가 담겨있는지도 확인해보겠습니다.

 

1. info

data['info']
{'TRD_DT': '/Date(1728313200000)/',
 'MKT_VAL': 21468444,
 'TRD_AMT': 301731,
 'CNT': 34}

 

2. list

data['list'][0]
{'IDX_CD': 'G10',
 'IDX_NM_KOR': 'WICS 에너지',
 'ALL_MKT_VAL': 21468444,
 'CMP_CD': '096770',
 'CMP_KOR': 'SK이노베이션',
 'MKT_VAL': 6347653,
 'WGT': 29.57,
 'S_WGT': 29.57,
 'CAL_WGT': 1.0,
 'SEC_CD': 'G10',
 'SEC_NM_KOR': '에너지',
 'SEQ': 1,
 'TOP60': 4,
 'APT_SHR_CNT': 53611930}

 

3. sector

data['sector']
[{'SEC_CD': 'G25', 'SEC_NM_KOR': '경기관련소비재', 'SEC_RATE': 9.85, 'IDX_RATE': 0},
 {'SEC_CD': 'G35', 'SEC_NM_KOR': '건강관리', 'SEC_RATE': 11.45, 'IDX_RATE': 0},
 {'SEC_CD': 'G50', 'SEC_NM_KOR': '커뮤니케이션서비스', 'SEC_RATE': 5.68, 'IDX_RATE': 0},
 {'SEC_CD': 'G40', 'SEC_NM_KOR': '금융', 'SEC_RATE': 9.98, 'IDX_RATE': 0},
 {'SEC_CD': 'G10', 'SEC_NM_KOR': '에너지', 'SEC_RATE': 1.66, 'IDX_RATE': 100.0},
 {'SEC_CD': 'G20', 'SEC_NM_KOR': '산업재', 'SEC_RATE': 14.24, 'IDX_RATE': 0},
 {'SEC_CD': 'G55', 'SEC_NM_KOR': '유틸리티', 'SEC_RATE': 1.09, 'IDX_RATE': 0},
 {'SEC_CD': 'G30', 'SEC_NM_KOR': '필수소비재', 'SEC_RATE': 2.15, 'IDX_RATE': 0},
 {'SEC_CD': 'G15', 'SEC_NM_KOR': '소재', 'SEC_RATE': 7.74, 'IDX_RATE': 0},
 {'SEC_CD': 'G45', 'SEC_NM_KOR': 'IT', 'SEC_RATE': 36.17, 'IDX_RATE': 0}]

 

4. size

data['size']
[{'SEC_CD': 'WMI510',
  'SEC_NM_KOR': 'WMI500 대형주',
  'SEC_RATE': 17.09,
  'IDX_RATE': 91.64},
 {'SEC_CD': 'WMI520',
  'SEC_NM_KOR': 'WMI500 중형주',
  'SEC_RATE': 30.89,
  'IDX_RATE': 8.36},
 {'SEC_CD': 'WMI530',
  'SEC_NM_KOR': 'WMI500 소형주',
  'SEC_RATE': 52.02,
  'IDX_RATE': 0}]

 

이와같이 list에는 해당 섹터의 구성종목 정보가, sector에는 각종 섹터의 코드 정보가 포함되어있습니다. 이 중 종목 정보가 단긴 list를 데이터프레임 형태로 변경해서 살펴보겠습니다. 판다스의 json_normlize() 함수를 사용하면 간단하게 json 형태의 데이터를 데이터 프레임 형태로 변경할 수 있습니다.

 

data_pd = pd.json_normalize(data['list'])

data_pd.head()

 

그럼 이제 에너지 섹터뿐만아니라, 모든 섹터의 구성종목을 받아오기 위한 작업을 진행해보겠습니다. for문을 이용하여 URL의 sec_cd 부분만 data['sector']에서 'SEC_CD' 정보를 하나씩 넣어주면 됩니다. tqdm() 함수를 사용하면 진행상황을 확인할 수 있습니다. 수집한 데이터를 concat으로 하나의 데이터 프레임으로 합쳐주고, 필요한 열(섹터 코드, 티커, 종목명, 섹터명)만 선택해줍니다. 마지막으로 기준일 열을 추가해줍니다.

 

import time
import json
import requests as rq
import pandas as pd
from tqdm import tqdm

sector_code = [item['SEC_CD'] for item in data['sector']]
# ['G25', 'G35', 'G50', 'G40', 'G10', 'G20', 'G55', 'G30', 'G15', 'G45']

data_sector = []

for i in tqdm(sector_code):
    url = f'''http://www.wiseindex.com/Index/GetIndexComponets?ceil_yn=0&dt={biz_day}&sec_cd={i}'''    
    data = rq.get(url).json()
    data_pd = pd.json_normalize(data['list'])

    data_sector.append(data_pd)

    time.sleep(2)

kor_sector = pd.concat(data_sector, axis = 0)
kor_sector = kor_sector[['IDX_CD', 'CMP_CD', 'CMP_KOR', 'SEC_NM_KOR']]
kor_sector['기준일'] = biz_day
kor_sector['기준일'] = pd.to_datetime(kor_sector['기준일'])

 

이렇게 크롤링한 데이터를 한국거래소 데이터를 적재한 것과 같이 테이블을 생성해서 적재해주어야합니다. kor_sector라는 테이블을 아래와 같이 생성하고, CMP_CD와 기준일을 PK로 설정해줍니다. CMP_CD는 티커정보이므로 겹칠일이 없고, 다만 크롤링을 할 때마다 같은 종목이 계속 수집이 될테니, biz_day도 함께 PK로 설정해주어야합니다.

 

2. MySQL DB에 수집한 데이터 적재

use stock_db;

create table kor_sector
(
    IDX_CD varchar(3),
    CMP_CD varchar(6),
    CMP_KOR varchar(20),
    SEC_NM_KOR varchar(10),
    기준일 date,
    primary key(CMP_CD, 기준일)
);

 

마지막으로 upsert 방식으로 수집한 데이터를 적재해줍니다.

import pymysql

con = pymysql.connect(user='root',
                      passwd='1234',
                      host='127.0.0.1',
                      db='stock_db',
                      charset='utf8')

mycursor = con.cursor()
query = f"""
    insert into kor_sector (IDX_CD, CMP_CD, CMP_KOR, SEC_NM_KOR, 기준일)
    values (%s,%s,%s,%s,%s) as new
    on duplicate key update
    IDX_CD = new.IDX_CD, CMP_KOR = new.CMP_KOR, SEC_NM_KOR = new.SEC_NM_KOR
"""

args = kor_sector.values.tolist()

mycursor.executemany(query, args)
con.commit()

con.close()

 

 

전체 코드

import time
import json
import requests as rq
import pandas as pd
from tqdm import tqdm
import pymysql

sector_code = [item['SEC_CD'] for item in data['sector']]
# ['G25', 'G35', 'G50', 'G40', 'G10', 'G20', 'G55', 'G30', 'G15', 'G45']

data_sector = []

for i in tqdm(sector_code):
    url = f'''http://www.wiseindex.com/Index/GetIndexComponets?ceil_yn=0&dt={biz_day}&sec_cd={i}'''    
    data = rq.get(url).json()
    data_pd = pd.json_normalize(data['list'])

    data_sector.append(data_pd)

    time.sleep(2)

kor_sector = pd.concat(data_sector, axis = 0)
kor_sector = kor_sector[['IDX_CD', 'CMP_CD', 'CMP_KOR', 'SEC_NM_KOR']]
kor_sector['기준일'] = biz_day
kor_sector['기준일'] = pd.to_datetime(kor_sector['기준일'])

con = pymysql.connect(user='root',
                      passwd='1234',
                      host='127.0.0.1',
                      db='stock_db',
                      charset='utf8')

mycursor = con.cursor()
query = f"""
    insert into kor_sector (IDX_CD, CMP_CD, CMP_KOR, SEC_NM_KOR, 기준일)
    values (%s,%s,%s,%s,%s) as new
    on duplicate key update
    IDX_CD = new.IDX_CD, CMP_KOR = new.CMP_KOR, SEC_NM_KOR = new.SEC_NM_KOR
"""

args = kor_sector.values.tolist()

mycursor.executemany(query, args)
con.commit()

con.close()

 

 

참고자료

https://github.com/hyunyulhenry/quant_py/blob/main/data_korea.ipynb

 

다음편

 

파이썬 퀀트투자(6): 네이버금융 수정주가 크롤링

주가 데이터는 투자를 함에 있어 반드시 필요한 데이터입니다. 인터넷에서 주가를 수집할 수 있는 방법은 매우 많지만, 퀀트 투자를 위한 백테스트나 종목선정을 위해서는 수정주가가 필요합니

coduking.tistory.com

 

 

댓글