주식 데이터를 필터링하고 랭킹을 매기는 함수: get_universe()
def get_universe():
df = execute_crawler()
# 데이터 전처리: 불필요한 문자 제거 및 N/A 값 처리
mapping = {',':'', 'N/A':'0'}
df.replace(mapping, regex=True, inplace=True)
# 분석에 사용할 컬럼 리스트
cols = ['거래량', '매출액', '매출액증가율', 'ROE', 'PER']
# 숫자 데이터 타입 변환
df[cols] = df[cols].astype(float)
# 조건에 맞는 종목만 필터링
df = df[(df['거래량'] > 0) &
(df['매출액'] > 0) &
(df['매출액증가율'] > 0) &
(df['ROE'] > 0) &
(df['PER'] > 0) &
(~df.종목명.str.contains("지주")) &
(~df.종목명.str.contains("홀딩스"))]
# PER의 역수를 구해 1/PER 컬럼 생성
df['1/PER'] = 1 / df['PER']
# ROE와 1/PER을 각각 랭킹
df['RANK_ROE'] = df['ROE'].rank(method='max', ascending=False)
df['RANK_1/PER'] = df['1/PER'].rank(method='max', ascending=False)
# 두 랭킹의 평균으로 최종 랭킹 계산
df['RANK_VALUE'] = (df['RANK_ROE'] + df['RANK_1/PER']) / 2
# RANK_VALUE에 따라 정렬하고 상위 200개의 종목 선택
df = df.sort_values(by=['RANK_VALUE'])
df.reset_index(inplace=True, drop=True)
df = df.loc[:199]
# 선택된 종목명 출력 및 엑셀 저장
df.to_excel('universe.xlsx')
print(df['종목명'].tolist())
return df['종목명'].tolist()
1. 주요 기능 설명
- 데이터 전처리: 크롤링한 데이터에 포함된 ,와 N/A 같은 불필요한 문자나 값을 제거하고, 필요한 컬럼들을 숫자(float) 형식으로 변환합니다.
- 필터링: 특정 조건을 만족하는 종목만 필터링합니다. 예를 들어, 거래량이나 매출액이 0보다 큰 종목만 남기고, ‘지주’나 ‘홀딩스’가 포함된 종목은 제외합니다.
- PER의 역수 계산: 저평가된 종목을 찾기 위해 PER(주가수익비율)의 역수를 계산하여 1/PER 컬럼을 만듭니다.
- 랭킹 계산: ROE(자기자본이익률)와 1/PER 값에 기반한 두 개의 랭킹을 각각 구한 후, 두 랭킹의 평균을 계산하여 종목의 최종 점수를 결정합니다.
- 상위 200개 종목 선택: 랭킹을 기준으로 상위 200개의 종목을 선택합니다.
2. 메인 실행부
if __name__ == "__main__":
print('start')
get_universe()
print('end')
- 프로그램이 시작될 때 get_universe() 함수를 호출하여 전체 과정을 실행합니다. start와 end를 출력하여 프로그램의 시작과 끝을 알 수 있습니다.
3. 전체 코드 및 실행결과
import pandas as pd
import requests
from bs4 import BeautifulSoup
import numpy as np
import pandas as dp
from datetime import datetime
BASE_URL = 'https://finance.naver.com/sise/sise_market_sum.nhn?sosok='
CODES = [0, 1]
START_PAGE = 1
fields = []
now = datetime.now()
formattedDate = now.strftime("%Y%m%d")
def execute_crawler():
df_total = []
for code in CODES:
res = requests.get(BASE_URL + str(CODES[0]))
page_soup = BeautifulSoup(res.text, 'lxml')
total_page_num = page_soup.select_one('td.pgRR > a')
total_page_num = int(total_page_num.get('href').split('=')[-1])
ipt_html = page_soup.select_one('div.subcnt_sise_item_top')
global fields
fields = [item.get('value') for item in ipt_html.select('input')]
result = [crawler(code, str(page)) for page in range(1, total_page_num + 1)]
df = pd.concat(result, axis=0, ignore_index=True)
df_total.append(df)
df_total = pd.concat(df_total)
df_total.reset_index(inplace=True, drop=True)
df_total.to_excel('NaverFinance.xlsx')
return df_total
def crawler(code, page):
global fields
data = {'menu': 'market_sum',
'fieldIds': fields,
'returnUrl': BASE_URL + str(code) + "&page=" + str(page)}
res = requests.post('https://finance.naver.com/sise/field_submit.nhn', data=data)
page_soup = BeautifulSoup(res.text, 'lxml')
table_html = page_soup.select_one('div.box_type_l')
header_data = [item.get_text().strip() for item in table_html.select('thead th')][1:-1]
inner_data = [item.get_text().strip() for item in table_html.find_all(lambda x:
(x.name == 'a' and
'tltle' in x.get('class', [])) or (x.name == 'td' and
'number' in x.get('class', []))
)]
no_data = [item.get_text().strip() for item in table_html.select('td.no')]
number_data = np.array(inner_data)
number_data.resize(len(no_data), len(header_data))
df = pd.DataFrame(data=number_data, columns=header_data)
return df
def get_universe():
df = execute_crawler()
mapping = {',':'', 'N/A':'0'}
df.replace(mapping, regex=True, inplace=True)
cols = ['거래량', '매출액', '매출액증가율', 'ROE', 'PER']
df[cols] = df[cols].astype(float)
df = df[(df['거래량'] > 0) & (df['매출액'] > 0) & (df['매출액증가율'] > 0) & (df['ROE'] > 0) & (df['PER'] > 0) & (~df.종목명.str.contains("지주")) & (~df.종목명.str.contains("홀딩스"))]
df['1/PER'] = 1 / df['PER']
df['RANK_ROE'] = df['ROE'].rank(method='max', ascending=False)
df['RANK_1/PER'] = df['1/PER'].rank(method='max', ascending=False)
df['RANK_VALUE'] = (df['RANK_ROE'] + df['RANK_1/PER']) / 2
df = df.sort_values(by=['RANK_VALUE'])
df.reset_index(inplace=True, drop=True)
df = df.loc[:199]
df.to_excel('universe.xlsx')
print(df['종목명'].tolist())
return df['종목명'].tolist()
if __name__ == "__main__":
print('start')
get_universe()
print('end')
4. 결론
이 코드는 Naver Finance에서 코스피 및 코스닥 종목 데이터를 수집하고, 특정 조건에 따라 데이터를 필터링하고 랭킹을 매긴 후, 상위 200개의 종목을 선정하여 엑셀 파일로 저장하는 과정을 수행합니다.
이 코드를 통해 실시간으로 다양한 주식 데이터를 분석하고, 특정 조건에 맞는 종목을 효율적으로 선정할 수 있습니다. Pandas와 BeautifulSoup을 사용한 데이터 크롤링 및 분석의 실용적인 예시라고 할 수 있습니다.