최근 주식과 트레이딩 알고리즘을 이용한 자동 주식 매매에 관심이 생기기 시작했다. 그래서 이번에 가볍게 관심 종목의 현재 주가를 알려주는 Slack 챗봇을 만들어 보기로 했다.

Slack 챗봇을 만들기 전에 우선 현재 주가를 실시간으로 어디서 어떻게 가져올 것인지 고민해봐야 한다. 처음에는 증권사에서 제공하는 OpenAPI를 이용해 HTS에 접속해서 현재가를 가져오려고 했지만 API가 가벼운 편은 아니기 때문에, 이후 가상머신에 해당 프로그램을 올리고 사용하기에는 부담이 있어 다른 방법을 사용하기로 했다.

당연하게도 크롤링을 통해 현재가 데이터만 scraping 하는 방식을 채택했다. 네이버 및 다음 증권 홈페이지에서는 실시간 주가 데이터를 제공해주기 때문에 특정 주기로 업데이트된 관심 종목의 주가를 알림받게 하려고 한다.

 


1. 관심 종목 코드 가져오기

다음은 삼성전자의 주가 데이터를 가져오기 위한 url이다. 주식을 아주 조금이라도 했다면 각 기업마다 종목코드가 존재한다는 것을 알 수 있다. 정확히는 증권표준코드로 한국거래소가 국제표준화기구가 정한 국제표준과 한국산업규격에 따라 증권 및 관련 금융상품에 대해 부여한 고유번호이다. 즉, 기업마다 종목코드가 중복될 일은 없으며 해당 종목코드로 기업을 찾을 수 있다. 

기업별 종목 코드는 한국거래소에서 엑셀 파일로 어려움없이 가져올 수 있다. 상장된 기업의 종목 코드를 모두 가져오고 싶다면 아래 링크로 접속해서 검색 옆의 EXCEL 버튼을 클릭해주면 된다.

 

대한민국 대표 기업공시채널 KIND

업종 전체 농업, 임업 및 어업 광업 제조업 - 식료품 제조업 - 음료 제조업 - 담배 제조업 - 섬유제품 제조업; 의복제외 - 의복, 의복액세서리 및 모피제품 제조업 - 가죽, 가방 및 신발 제조업 - 목

kind.krx.co.kr

일단은 간단하게 현재가를 실시간으로 받아오고 싶었기 때문에 현재 내가 관심있기 지켜보고 있는 "삼성전자", "카카오", "NAVER"의 종목코드를 txt 파일 형식으로 저장하였다.

 

 


2. 텍스트 파일 불러오기

우선 파이썬 파일을 하나 생성하여 관심 종목 코드 텍스트 파일과 동일한 경로에 저장하였다. 이후 파이썬 파일에서 텍스트 파일을 불러와 종목코드를 리스트 형식으로 저장하였다.

def get_interest_code_list():
    f = open("interest_stock_list.txt", "rt")
    interest_stock_list = f.read().split()
    f.close()
    return interest_stock_list

read() 함수를 이용해 텍스트 파일을 모두 읽어들인 뒤, split() 함수를 이용해 공백 기준으로 잘라 리스트 형태로 저장하였다. 이후 관심 종목 코드가 리스트화 되어 저장되어 있는 interest_stock_list를 반환한다.

 

 


3. 네이버 증권 페이지에서 현재가 가져오기

앞서 get_interest_code_list() 함수를 사용해 관심 종목 코드가 저장되어 있는 리스트를 다른 변수에 초기화 한다. 이후 list iterator를 이용해 for문을 돌면서 각 종목별 증권 페이지에 접속해 현재가를 가져오면 된다. 먼저 간단하게 종목 코드를 인자로 받으면 해당 종목 코드의 증권 페이지에 연결하여 HTML 코드를 반환하는 함수를 작성해보았다. 기존에 크롤링을 조금 해봤다면 이 코드를 쉽게 이해할 수 있을 것이다.

def connect_finance_page(company_code):
    url = "https://finance.naver.com/item/main.nhn?code=" + company_code
    resp = requests.get(url)
    soup = BeautifulSoup(resp.text, "html.parser")
    return soup

 

특정 종목 코드의 증권 페이지 HTML 코드가 담긴 soup 객체를 반환 받았으면 해당 코드에서 현재가를 어디에 저장하고 있는지 확인해야 한다. 일반적으로 아래 사진처럼 현재가가 나와 있어 ctrl + shift + i 로 해당 코드 부분을 확인하면...

음....

 

참 가져오기 어렵게 만들어놨다. 하지만 코드를 조금 더 살펴보니 아래와 같이 종목명, 종목코드, 현재가 뿐만 아니라 고가, 저가, 거래량, 거래 대금 등의 데이터 정보를 숨겨논걸 확인할 수 있었다. 심지어 class 이름도 blind 이다. 이 데이터를 이용해 현재가를 가져오려고 한다.

 

먼저 connect_finance_page를 통해 해당 종목 증권 페이지의 HTML 코드를 가져온 다음, class 이름이 blind인 "d1"태그를 가져온다. 이후, find_all 함수를 이용해 모든 "dd" 태그의 값들을 가져와 리스트 형태로 저장한다.

def get_all_info(company_code):
    html = connect_finance_page(company_code)
    current_info = html.find("dl", {"class": "blind"})
    current_info = current_info.find_all("dd")  # dict 형태로 변경
    return current_info

 

"dd" 태그가 달린 리스트의 요소들을 그대로 사용하기엔 이후 어떤 tag 값(현재가, 고가, 저가 등)을 가지는지, 구분하기 어려워질 것 같아 dict로 데이터 형식을 변환하려고 한다. change_info_format은 "dd" 태그가 달린 종목 데이터를 리스트 형식으로 받아 사전 형태로 변환하여 반환하는 함수이다.

def change_info_format(current_info):
    info_dictionary = {"Date": current_info[0].get_text()}
    current_info.remove(current_info[0])

    for i, item in enumerate(current_info):
        current_info[i] = item.get_text().split()

    for i, item in enumerate(current_info):
        info_dictionary[item[0]] = item[1]

    return info_dictionary

위 코드에서 날짜와 관련된 정보는 필요하지 않기 때문에 list의 remove 함수를 사용해 제거해줬고, "dd" 태그에 담긴 값을 가져와 split() 함수를 이용해 공백을 분리하고 사전 형태로 변환하였다. 결과적으로 현재가를 가져오는 코드는 다음과 같이 수정될 수 있다.

# 1. 종목 데이터 가져오기
def get_all_info(company_code):
    html = connect_finance_page(company_code)
    current_info = html.find("dl", {"class": "blind"})
    current_info = change_info_format(current_info.find_all("dd"))  # dict 형태로 변경
    return current_info


# 1-1. url 연결
def connect_finance_page(company_code):
    url = "https://finance.naver.com/item/main.nhn?code=" + company_code
    resp = requests.get(url)
    soup = BeautifulSoup(resp.text, "html.parser")
    return soup


# 1-2. 종목 데이터 리스트 -> 사전 형태로 변경
def change_info_format(current_info):
    info_dictionary = {"Date": current_info[0].get_text()}
    current_info.remove(current_info[0])

    for i, item in enumerate(current_info):
        current_info[i] = item.get_text().split()

    for i, item in enumerate(current_info):
        info_dictionary[item[0]] = item[1]

    return info_dictionary

 

 


4. 현재가 출력하기

이제 남은 일은 Slack의 챗봇으로 해당 데이터를 전달하기만 하면 된다. 다만, 그 전에 해당 코드가 정상적으로 작동하는지 확인해보자. slack_bot_get_current_price() 함수는 관심 종목 코드를 텍스트 파일로부터 불러온 후, 네이버 증권 페이지에 연결하여 현재가를 가져와 출력하는 함수이다.

def slack_bot_get_current_price():
    interest_stock_list = get_interest_code_list()
    for code in interest_stock_list:
        info = get_all_info(code)
        print(info["종목명"] + " 현재가 : " + info["현재가"])

 

잘 가져오는 듯 하다.

 

 


# 현재가 가져오기
def slack_bot_get_current_price():
    interest_stock_list = get_interest_code_list()
    for code in interest_stock_list:
        info = get_all_info(code)
        print(info["종목명"] + " 현재가 : " + info["현재가"])

# 0. 관심 종목 코드 가져오기
def get_interest_code_list():
    f = open("interest_stock_list.txt", "rt")
    interest_stock_list = f.read().split()
    f.close()
    return interest_stock_list


# 1. 종목 데이터 가져오기
def get_all_info(company_code):
    html = connect_finance_page(company_code)
    current_info = html.find("dl", {"class": "blind"})
    current_info = change_info_format(current_info.find_all("dd"))  # dict 형태로 변경
    return current_info


# 1-1. url 연결
def connect_finance_page(company_code):
    url = "https://finance.naver.com/item/main.nhn?code=" + company_code
    resp = requests.get(url)
    soup = BeautifulSoup(resp.text, "html.parser")
    return soup


# 1-2. 종목 데이터 리스트 -> 사전 형태로 변경
def change_info_format(current_info):
    info_dictionary = {"Date": current_info[0].get_text()}
    current_info.remove(current_info[0])

    for i, item in enumerate(current_info):
        current_info[i] = item.get_text().split()

    for i, item in enumerate(current_info):
        info_dictionary[item[0]] = item[1]

    return info_dictionary
    
    
# 파일 실행
if __name__ == "__main__":
	slack_bot_get_current_price()
728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 라이프코리아트위터 공유하기
  • shared
  • 카카오스토리 공유하기