본문 바로가기

Python/주가 크롤링 프로그램

주가 크롤링 (네이버 주식)

import sys
import pandas as pd
import xlrd

from datetime import datetime

import requests
import bs4


code_list = ['005930']

 

if datetime.now() > last_date_time:

    for code_number in code_list:
        total_data_list = []

        my_headers = {
            "referer": "https://finance.naver.com/item/sise_day.nhn?code={}&page=1".format(code_number),
            "upgrade-insecure-requests": ,
            "user-agent":  
        }

        
        for page_number in range(1, 21):
            url = "https://finance.naver.com/item/sise_day.nhn?code={0}&page={1}".format(code_number, page_number)
            res = requests.get(url = url, headers = my_headers)

            soup = bs4.BeautifulSoup(res.text)
            tr_elements = soup.select("table.type2 >  tr[onmouseover='mouseOver(this)']")

 

            current_date_time_set = set()  #현재페이지(1p)의 date_time_set. 추후 현재날짜와 비교용도로 사용
            for tr in tr_elements:
                td_elements = e.select("td")
                data_list = [] 

                for i, td_e in enumerate(td_elements):
                    if i == 0 : #날짜값 index == 0, 즉 i=0인 data(날짜 data)만 관리하겠다..
                        current_date_time_set.add(td_e.text.strip()) #날짜 Data 추가
                    
                    else :
                        data_list.append(td_e.text.strip().replace(",","")) #data int로 바꿔줘야 함. 먼저 , 없애고..      
                data_list_int = [data_list[0], int(data_list[1]), int(data_list[2]), int(data_list[3]), int(data_list[4]), int(data_list[5]), int(data_list[6])]
                total_data_list.append(data_list_int)

 


1. code_list = [] 에 해당하는 주식을 크롤링.

참조 사이트는 네이버 금융 > 시세 > 일별 시세이다.

 

2. total_date_list = [] 

빈 list를 먼저 정의. 추후 크롤링해온 주가를 여기에 추가하는 개념.

ex) 005930 주식코드를 크롤링하여 data_list에 저장. (for문 안에서) -> 이후 for문이 끝나면서 total_data_list에 추가. 

-> for문이 반복되면서 total_data_list에 여러 주식 코드들의 주가를 저장.

 

3. my_header를 통해 불러오는 사이트의 기본 정보들을 입력

 - 일별 시세 Html의 구조는 리스트를 클릭할때마다 새로 그 부분의 html만 업로드 되는 형식.

 - Network를 켜고 클릭해보면 아래 사진과 같이 sise_day가 새로 뜸

sise_day를 눌러보면 General에 Request URL 등과 같이 Request에 필요한 정보들을 얻을 수 있다.

이 때  "referer": "https://finance.naver.com/item/sise_day.nhn?code={}&page=1".format(code_number) 와 같이 지정했는데, 이는 홈페이지의 구조가 referer에 주식코드가 들어가기 때문이다.

code_list에 보유 주식 코드를 입력하고, for code_number in code_list 문을 이용해 코드 하나하나 크롤링 해오는 개념.

 

4. 이후 두번째 for문. :  for page_number in range(1, 21): 

이는 page의 range를 설정. 결국 1 page부터 20 page까지 일일이 클릭해 데이터를 복사해오는 개념이다.

 

url = "https://finance.naver.com/item/sise_day.nhn?code={0}&page={1}".format(code_number, page_number)
res = requests.get(url = url, headers = my_headers)

 

Url 구성을 보면 알 수 있듯, code_number뿐 아니라 page_number 역시 url에 들어가 있다. 그렇기에 위와 같이 for문을 통해 (1,21)에 해당하는 page를 전부 끌고 오는 것.

 

 

 

여기서 추가로 BeautifulSoup이라는 크롤링에 특화된 패키지를 사용한다.

먼저 request를 통해 HTML 문서에 담긴 내용을 가져 오도록 request한다. (requests library 설치 필요)

 : res = requests.get(url = url, headers = my_headers) 

 

여기까지 하면 해당 url, header에 맞는 HTML을 불러올 수 있다.

Res만 Print 했을 시 Response [200]이 뜨면 정상적으로 불러온 것이다.

이제 이를 beautifulsoup을 이용해 text만 따로 정보를 추출한다.

이 과정을 하는 이유는 Requests를 이용하면 HTML의 정보를 얻어올 수는 있지만 Python에서 활용가능한 객체 구조로 만들어 주지는 못하기 때문이다.

그래서 beautifulsoup을 이용해 python이 이해할 수 있는 객체구조로 만들어주는 것이다.

 

: soup = bs4.BeautifulSoup(res.text)

 

그리고 HTML 구조를 보면 아래와 같이 많은 하위구조가 존재한다.

우리가 원하는 값(79,400 : 2021.07.09 삼성전자 종가)를 가져와야 하기 때문에 아래와 같이 tr_elements를 새로 정의한다.

 : tr_elements = soup.select("table.type2 >  tr[onmouseover='mouseOver(this)']")

 

이렇게 하면 table에서 class="type2"를, 그리고 그중에서도 tr onmouseover="mouseOver(this)"에 해당하는 데이터만 아래와 같이 가져온다.

밑에 일부 중략..

 

그 후

for tr in tr_elements:
    td_elements = tr.select("td")

 

를 통해 각각의 tr_elements에서 td가 붙은 것만 데이터를 뽑아낸다. (td가 들어가 있는 곳에 우리가 원하는 데이터가 있기 때문)

 

밑에 일부 중략..

for td_e in td_elements:

    print(td_e)

를 하면 아래와 같이 나온다.

 

데이터를 불러오는 것을 보면

맨 첫번째가 2021.07.09 데이터, 두번째가 2021.07.08 데이터 ... 형식인 것을 알 수 있다.

즉, 이를 enumerate 함수를 이용하면 td_elements를 index화하여 나타낼 수 있다.

그리고, i=0이 날짜값 index임을 알 수 있다.

 


current_date_time_set = set()  #현재페이지(1p)의 date_time_set
test_1 = set()
test_2 = set()
test_3 = set()
test_4 = set()
test_5 = set()
test_6 = set()
test_7 = set()
test_8 = set()


for e in tr_elements:
    td_elements = e.select("td")
       
    for i, td_e in enumerate(td_elements):
        if i == 0 : #날짜값 index == 0, 즉 i=0인 data(날짜 data)만 관리하겠다..
            current_date_time_set.add(td_e.text.strip()) #날짜 Data 추가
            
        if i == 1 :
            test_1.add(td_e.text.strip())
            
        if i == 2 :
            test_2.add(td_e.text.strip())
            
        if i == 3 :
            test_3.add(td_e.text.strip())

        if i == 4 :
            test_4.add(td_e.text.strip())
            
        if i == 5 :
            test_5.add(td_e.text.strip())
            
        if i == 6 :
            test_6.add(td_e.text.strip())

        if i == 7 :
            test_7.add(td_e.text.strip())
            
        if i == 8 :
            test_8.add(td_e.text.strip())         


데이터가 어떻게 구성되는지 확인하기 위해 위와 같이 코드를 짜보았다. 

이렇게 각각의 데이터가 나오는데, 다 중구난방으로 나온다.. 그렇기에 정렬기준이 되는 날짜(i=0)를 기준으로 데이터를 관리해야 한다.

(날짜 set인 current_date_time_set도 정렬이 되어있지 않고,, test_1~6까지도 정렬이 되어 있지 않음.)

 

그래서 아래와 같이 관리한다.

 


total_data_list = []
current_date_time_set = set()  #현재페이지(1p)의 date_time_set

for tr in tr_elements:
    td_elements = tr.select("td")
    data_list = [] 

    for i, td_e in enumerate(td_elements):
        if i == 0 : # i=0인 data(날짜 data)만 관리하겠다..
            current_date_time_set.add(td_e.text.strip()) #날짜 Data 추가
        
        data_list.append(td_e.text.strip().replace(",","")) #data int로 바꿔줘야 함. 먼저 , 없애고..                          
    data_list_int = [data_list[0], int(data_list[1]), int(data_list[2]), int(data_list[3]), int(data_list[4]), int(data_list[5]), int(data_list[6])]
    total_data_list.append(data_list_int)


날짜 Data는 current_date_time_set에 따로 저장하고 실제 관심대상 data는 total_data_list에 저장한다.

 

물론 여기서 data_list[0]이 날짜 data로 쓰이지만 따로 currnet_date_time_set을 만든 것은 추후 날짜비교를 통해 주가 업데이트를 할지 여부에 사용되기 때문이다.