feat: 10장 주식 데이터 조회 추가
This commit is contained in:
		
							parent
							
								
									50c740501e
								
							
						
					
					
						commit
						18016bfdec
					
				
							
								
								
									
										119
									
								
								example/10-stock-data.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								example/10-stock-data.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | ||||
| import logging | ||||
| import re | ||||
| from io import BytesIO | ||||
| 
 | ||||
| import numpy as np | ||||
| import pandas as pd | ||||
| import requests as rq | ||||
| from bs4 import BeautifulSoup | ||||
| 
 | ||||
| GEN_OTP_URL = 'http://data.krx.co.kr/comm/fileDn/GenerateOTP/generate.cmd' | ||||
| DOWN_URL = 'http://data.krx.co.kr/comm/fileDn/download_csv/download.cmd' | ||||
| 
 | ||||
| # 최근 영업일을 가져옴 | ||||
| def get_latest_biz_day(): | ||||
|     url = 'https://finance.naver.com/sise/sise_deposit.nhn' | ||||
|     data = rq.post(url) | ||||
|     data_html = BeautifulSoup(data.content, 'lxml') | ||||
|     parse_day = data_html.select_one('div.subtop_sise_graph2 > ul.subtop_chart_note > li > span.tah').text | ||||
|     biz_day = re.findall('[0-9]+', parse_day) | ||||
|     biz_day = ''.join(biz_day) | ||||
|     return biz_day | ||||
| 
 | ||||
| 
 | ||||
| # 업종 분류 현황 가져옴 | ||||
| def get_stock_data(biz_day, mkt_id): | ||||
|     # logging.basicConfig(level=logging.DEBUG) | ||||
|     gen_otp_data = { | ||||
|         'locale': 'ko_KR', | ||||
|         'mktId': mkt_id, # STK: 코스피, KSQ: 코스닥 | ||||
|         'trdDd': biz_day, | ||||
|         'money': '1', | ||||
|         'csvxls_isNo': 'false', | ||||
|         'name': 'fileDown', | ||||
|         'url': 'dbms/MDC/STAT/standard/MDCSTAT03901' | ||||
|     } | ||||
|     headers = { | ||||
|         'Referer': 'http://data.krx.co.kr/contents/MDC/MDI/mdiLoader/index.cmd?menuId=MDC0201050201', | ||||
|         'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36' | ||||
|     } | ||||
| 
 | ||||
|     otp = rq.post(url=GEN_OTP_URL, data=gen_otp_data, headers=headers, verify=False) | ||||
|     # # 요청 디버깅 | ||||
|     # print("===== Request Details =====") | ||||
|     # print(f"Method: {otp.request.method}") | ||||
|     # print(f"URL: {otp.request.url}") | ||||
|     # print(f"Headers: {otp.request.headers}") | ||||
|     # print(f"Body: {otp.request.body}") | ||||
|     # | ||||
|     # # 응답 디버깅 | ||||
|     # print("===== Response Details =====") | ||||
|     # print(f"Status Code: {otp.status_code}") | ||||
|     # print(f"Headers: {otp.headers}") | ||||
|     # print(f"Body: {otp.text}") | ||||
| 
 | ||||
|     down_sector = rq.post(url=DOWN_URL, data={'code': otp.text}, headers=headers) | ||||
|     return pd.read_csv(BytesIO(down_sector.content), encoding='EUC-KR') | ||||
| 
 | ||||
| 
 | ||||
| # 개별 지표 조회 | ||||
| def get_ind_stock_data(biz_day): | ||||
|     gen_otp_data = { | ||||
|         'locale': 'ko_KR', | ||||
|         'searchType': '1', | ||||
|         'mktId': 'ALL', | ||||
|         'trdDd': biz_day, | ||||
|         'csvxls_isNo': 'false', | ||||
|         'name': 'fileDown', | ||||
|         'url': 'dbms/MDC/STAT/standard/MDCSTAT03501' | ||||
|     } | ||||
|     headers = { | ||||
|         'Referer': 'http://data.krx.co.kr/contents/MDC/MDI/mdiLoader/index.cmd?menuId=MDC0201050201', | ||||
|         'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36' | ||||
|     } | ||||
| 
 | ||||
|     otp = rq.post(url=GEN_OTP_URL, data=gen_otp_data, headers=headers, verify=False) | ||||
| 
 | ||||
|     down_ind_sector = rq.post(url=DOWN_URL, data={'code': otp.text}, headers=headers) | ||||
|     return pd.read_csv(BytesIO(down_ind_sector.content), encoding='EUC-KR') | ||||
| 
 | ||||
| 
 | ||||
| def get_total_stock_data(biz_day): | ||||
|     # 업종 분류 현황(코스피, 코스닥) | ||||
|     sector_stk = get_stock_data(biz_day, 'stk') | ||||
|     sector_ksq = get_stock_data(biz_day, 'ksq') | ||||
|     # 각각 조회 후 합침 | ||||
|     krx_sector = pd.concat([sector_stk, sector_ksq]).reset_index(drop=True) | ||||
|     krx_sector['종목명'] = krx_sector['종목명'].str.strip() | ||||
|     krx_sector['기준일'] = biz_day | ||||
| 
 | ||||
|     # 개별 지표 조회 | ||||
|     krx_ind = get_ind_stock_data(biz_day) | ||||
|     krx_ind['종목명'] = krx_ind['종목명'].str.strip() | ||||
|     krx_ind['기준일'] = biz_day | ||||
| 
 | ||||
|     # 데이터 정리 | ||||
|     # 종목, 개별 중 한군데만 있는 데이터 삭제(선박펀드, 광물펀드, 해외종목 등) | ||||
|     diff = list(set(krx_sector['종목명']).symmetric_difference(set(krx_ind['종목명']))) | ||||
|     kor_ticket = pd.merge(krx_sector, krx_ind, on=krx_sector.columns.intersection(krx_ind.columns).tolist(), how='outer') | ||||
|     # 일반적인 종목과 SPAC, 우선주, 리츠, 기타 주식을 구분 | ||||
|     kor_ticket['종목구분'] = np.where(kor_ticket['종목명'].str.contains('스팩|제[0-9]+호'), '스팩', | ||||
|             np.where(kor_ticket['종목코드'].str[-1:] != '0', '우선주', | ||||
|                      np.where(kor_ticket['종목명'].str.endswith('리츠'), '리츠', | ||||
|                               np.where(kor_ticket['종목명'].isin(diff), '기타', | ||||
|                                        '보통주' | ||||
|             )))) | ||||
|     kor_ticket = kor_ticket.reset_index(drop=True) | ||||
|     kor_ticket.columns = kor_ticket.columns.str.replace(' ', '') | ||||
|     kor_ticket = kor_ticket[['종목코드', '종목명', '시장구분', '종가', | ||||
|                              '시가총액', '기준일', 'EPS', '선행EPS', 'BPS', '주당배당금', '종목구분']] | ||||
|     kor_ticket = kor_ticket.replace({np.nan: None}) | ||||
|     kor_ticket['기준일'] = pd.to_datetime(kor_ticket['기준일']) | ||||
|     return kor_ticket | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     latest_biz_day = get_latest_biz_day() | ||||
|     data = get_total_stock_data(latest_biz_day) | ||||
|     print(data) | ||||
| 
 | ||||
| 
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user