주식 일 데이터 가져오기
- 상황
- 주식 투자자 김족박 씨는 종목 발굴에 관심이 많습니다. 매일매일 전체 종목의 시가/저가/고가/종가/등락률을 확인하고 내일의 투자전략을 수립하고 싶어합니다.
- 시장의 흐름(실제)이 본인의 투자 모델(예측)과 얼마나 벌어져 있는지 체크하고 이를 본인의 투자 모형에 반영하기 위해서 입니다.
- 하지만 매일매일 770개 가까이 되는 KOSPI 종목의 가격을 확인하는 것은 꽤나 번거로운 일입니다.
- 해결
- 지인 중 국내 최고의 금융 IT 서비스 기업을 지향하는 IBK시스템 직원인 이태리 대리에게 이런게 가능할지 물어봤습니다.
- 가능합니다! 역시 유능한 IBK시스템 직원입니다. 김족박씨와 이태리 씨는 함께 주식투자 모델을 만들어 보기로 결정했습니다.
1. 데이터를 어디서 가져오지?
- 일단 간단하게 네x버에서 가져올 수 있을 것 같네요.
- 일단 데이터를 주워오기 위한 방법을 찾아내기 위해서 브라우저의 개발자 도구를 활용해서 요청/응답 규칙을 찾아냅니다.
- 이 주소를 사용할 수 있어 보입니다. http://finance.naver.com/item/sise.nhn?code=053800
- 응답 데이터 중 아래 부분을 사용하면 될것 같습니다.
<dl class="blind"> <dt>종목 시세 정보</dt> <dd>2017년 05월 04일 16시 10분 기준 장마감</dd> <dd>종목명 안랩</dd> <dd>종목코드 053800 코스닥</dd> <dd>현재가 59,900 전일대비 하락 300 마이너스 0.50 퍼센트</dd> <dd>전일가 60,200</dd> <dd>시가 59,400</dd> <dd>고가 61,800</dd> <dd>상한가 78,200</dd> <dd>저가 58,400</dd> <dd>하한가 42,200</dd> <dd>거래량 924,476</dd> <dd>거래대금 55,683백만</dd> </dl>
- 위 주소의 code 부분에 종목코드를 넣고 요청을 하면 나오는 응답에서 종목시세 부분을 가져와 저장하는 방식으로 하는 것으로 계획합니다.
- 전체 종목 도메인의 데이터는? 한국거래소(KRX) http://kind.krx.co.kr/corpgeneral/corpList.do?method=loadInitPage
2. 데이터를 어떻게 가져오지?
- 웹 스크래핑에 많이 활용되는 파이썬 프로그래밍 언어를 사용해 보려고 합니다.
- 조금 찾아보니 풍부한 라이브러리로 간단하게 개발이 가능할 것 같습니다.
- 여러가지 레퍼런스도 아주 많아 보입니다. 좋습니다.
- HTTP 요청은 requests를, 응답으로 들어온 HTML 파싱은 beautifulsoup4 라이브러리를 활용하면 쉽게 될것 같습니다.
- 종목 데이터
- 종목 데이터는 KRX에서 다운로드 받은 엑셀 파일을 읽어옵니다.
- !주의! 아래에 프로그램 코드가 나옵니다. 놀라지 마세요.
from bs4 import BeautifulSoup import codecs f = codecs.open('상장법인목록.xls', encoding='euc-kr') lines = f.readlines() table = BeautifulSoup("".join(lines), 'lxml').find('table')
- 확인해보니 엑셀 파일 안에는 HTML 형식의 데이터가 들어 있었습니다. 우리가 필요로하는 ‘종목코드’ 정보 부분은 ‘table’ 태그 부분에 있었습니다.
- 엑셀 파일의 인코딩이 EUC-KR로 되어 있어서 읽어오는데 번거로웠습니다. 아 제발 UTF-8을 사용합시다.
- 시세 데이터
- 네x버에서 조회해옵니다.
import requests from bs4 import beautifulsoup def get_today_price_data(code): sample_url = "http://finance.naver.com/item/sise.nhn?code={}".format(code) r = requests.post(sample_url) code = r.text soup = BeautifulSoup(code, 'lxml') dls = soup.findAll("dl", { "class" : "blind" }) dds = dls[0].find_all('dd') print(dds[1] # 종목명 , dds[3] # 현재가 , dds[4] # 전일종가 , dds[5] # 시가 , dds[6] # 고가 , dds[8] # 저가 , dds[10] # 거래량 , dds[11]) return dds[1].text, dds[3].text, dds[4].text, dds[5].text, dds[6].text, dds[8].text, dds[10].text, dds[11].text
- 시험해보기
price_data = get_today_price_data('053800') print(price_data)
- 결과
(‘종목명 안랩’, ‘현재가 59,900 전일대비 하락 300 마이너스 0.50 퍼센트’, ‘전일가 60,200’, ‘시가 59,400’, ‘고가 61,800’, ‘저가 58,400’, ‘거래량 924,476’, ‘거래대금 55,683백만’) - 데이터가 그리 깔끔하지 않습니다. 제목과 내용이 함께 들어가 있어서 조금 더 처리가 필요해 보입니다.
- Web API 방식으로 필요로하는 데이터만 가져올 수 있다면 가장 편하겠지만..필요한건 돈을 주고 사거나 스스로 처리해야겠죠.
- 제목과 내용이 붙어있는 데이터를 나눠서 읽을 수 있도록 함수를 하나 만들어 봅니다.
def parse_price_data(price_data_raw): prices = list(map(lambda x: x.split(' ')[1].replace(',', '').replace('백만', '000'), price_data)) return {'price': prices[1], 'yesterday_price': prices[2], 'start_price': prices[3], 'high_price': prices[4], 'low_price': prices[5], 'volume': prices[6], 'turnover': prices[7]}
- 이제 부품들이 모두 준비된 것 같습니다.
3. 데이터를 어디에 저장할까?
- 일단 종목 마스터(종목코드, 종목명 등) 간단한 데이터는 경량 데이터베이스인 SQLite 에 저장합니다. 상대적으로 변경이 자주 발생하지 않기 때문입니다.
- 테이블을 만듭니다.
import sqlite3 conn = sqlite3.connect('stock_codes.db') c = conn.cursor() # Drop table c.execute('''DROP TABLE stocks''') # Create table c.execute('''CREATE TABLE stocks (name text, codes text, ipo_date date)''')
- 종목 데이터 읽은 것을 저장합니다.
rows = table.find_all('tr') for row in rows: cols = row.find_all('td') if len(cols) > 4: c.execute("INSERT INTO stocks VALUES (?, ?, ?)", [cols[0].text, cols[1].text, cols[4].text]) conn.commit() conn.close()
- 시세 데이터는 RDB에 저장합니다.
- MySQL DB에 접속하고 테이블을 만듭니다.
import mysql.connector from sqlalchemy import create_engine pwd = getpass("DB Password: ") cnx_str = 'mysql+mysqlconnector://samsee:'+pwd+'@xxx.xxx.xxx.xxx/scrap4' engine = create_engine(cnx_str, echo=False) con = engine.connect() sql = ''' CREATE TABLE `scrap4`.`STOCK_PRICE` ( `DATE` DATE NOT NULL, `STOCK_CD` VARCHAR(6) NOT NULL, `PRICE` DECIMAL(9) NULL, `YESTERDAY_PRICE` DECIMAL(9) NULL, `START_PRICE` DECIMAL(9) NULL, `HIGH_PRICE` DECIMAL(9) NULL, `LOW_PRICE` DECIMAL(9) NULL, `VOLUME` DECIMAL(9) NULL, `TURNOVER` DECIMAL(12) NULL, PRIMARY KEY (`DATE`, `STOCK_CD`)) ''' con.execute(sql)
- 수집된 데이터 전체를 insert 합니다.
from datetime import datetime today = datetime.today() ins_sql = ''' insert into STOCK_PRICE (`date`, `stock_cd`, `price`, `yesterday_price`, `start_price`, `high_price`, `low_price`, `volume`, `turnover`) values (%s,%s,%s,%s,%s,%s,%s,%s,%s) ''' values = (today.strftime('%Y-%m-%d'), code, price_data['price'], price_data['yesterday_price'], price_data['start_price'], price_data['high_price'], price_data['low_price'], price_data['volume'], price_data['turnover']) con.execute(ins_sql, values)
- 이제 모두 모아서 돌려봅니다.
conn = sqlite3.connect('stock_codes.db') cnx_str = 'mysql+mysqlconnector://samsee:'+pwd+'@xxx.xxx.xxx.xxx/scrap4' engine = create_engine(cnx_str, echo=False) con = engine.connect() read_sql = "SELECT * FROM stocks" df_stocks = pd.read_sql(read_sql, conn) today = '2017-05-08' for index, row in df_stocks.iterrows(): # print(row['codes']) price_in_raw = get_today_price_data(row['codes']) price_data = parse_price_data(price_in_raw) ins_price(row['codes'], today, price_data) con.close() conn.close()
4. 데이터 분석하기
- 이제 모든 데이터가 준비되었습니다. 몇 가지 방식으로 분석을 해봅시다.
- 데이터 분석에는 pandas 라이브러리와 matplotlib 시각화가 도움이 됩니다.
- 데이터 읽어오기
import pandas as pd import matplotlib cnx_str = 'mysql+mysqlconnector://samsee:'+pwd+'@xxx.xxx.xxx.xxx/scrap4' engine = create_engine(cnx_str, echo=False) con = engine.connect() sql = 'SELECT * FROM scrap4.STOCK_PRICE WHERE DATE = "2017-05-08"' df = pd.read_sql(sql, con)
- 상승률/하락률 분포
df['change'] = (df['PRICE'] - df['START_PRICE']) / df['START_PRICE'] * 100 df.replace([np.inf, -np.inf], 0)['change'].hist(bins=100)
> 결과
정리
- 웹 스크래핑을 통해 데이터를 가져오고 처리한 뒤 분석하는 전체 과정을 살펴보았습니다.
- 파이썬 언어와 각종 라이브러리를 활용하여 적은 코딩으로 원하는 프로그램을 만들 수 있었습니다.
- 다음으로는 웹 스크래핑을 위한 파이썬 개발환경 설정을 알아보겠습니다.
Tips
- 크롤링(Crawling)과 스크래핑(Scraping)의 차이
- 양쪽 모두 웹 사이트의 정보를 자동으로 가져오는 방법입니다.
- 스크래핑은 특정 목적의 정보를 가져오기 위한 방법이라고 볼 수 있습니다. 보통 하나의 URL에 대해서 반복적인 요청을 하고 거기서 나온 데이터를 정규화된 데이터베이스에 저장하는 형태로 이루어집니다.
- 반면 크롤링은 사이트에 어떤 정보가 있는지 찾고 인덱싱을 하는 것을 목적으로 합니다. 구글이나 기타 다른 검색 엔진에서 크롤러라고 불리우는 소프트웨어 로봇이 인터넷을 돌아다니며 해당 페이지에 어떤 정보가 있는지 확인하고 저장합니다.
- 보통 우리가 하는 것은 크롤링 보다는 스크래핑에 가깝다고 볼 수 있을 것입니다.