본문 바로가기
Programming Basics

[웹 크롤링] 주식 일별 시세를 데이터프레임으로 저장하기

by ISLA! 2023. 8. 5.

주식 일별 시세 >> dataframe으로 결합하기

 

다음과 같은 종목별 일별 시세 내용을 데이터 프레임으로 저장할 수 있도록 크롤링 해보자

 

1. 라이브러리 import

import requests
from bs4 import BeautifulSoup
import pandas as pd
from fake_useragent import UserAgent

 

 

2. 데이터를 가져올 수 있는 함수 정의

🔎 getData()

  • 함수의 입력 파라미터는 다음과 같다
    • url: 데이터를 스크래핑할 웹 페이지의 URL
    • com_code: 크롤링할 종목코드
    • soup: (다른 함수에서 return 할 값, 다른 함수 참고)
    • page: 스크래핑할 페이지 수 (예, 1 페이지부터 ~ 10페이지까지 크롤링할 경우 >> 10)
  • df 와 count 변수를 초기화하고 시작
    • df : 크롤링한 데이터를 저장하기 위한 데이터프레임 (처음엔 아무것도 없으니 none)
    • count : 원하는 페이지까지 크롤링하기 위해 설정(여기서는 10페이지까지 크롤링할 예정)
  • f'{url}&page={page}': 문자열 포매팅을 사용하여 요청할 URL을 구성
    • url은 웹 페이지의 기본 URL이며, page는 요청할 페이지 번호
    • age 변수의 값을 해당 URL에 포함시킨 형태로 요청을 보내게 됨
    • 기본적으로 마지막 페이지까지 데이터를 추출하는 경우를 고려하여 만든 것
  • 반복문 
    • page 값이 1부터 page + 1 의 값까지 번위에서 반복하는 루프 시작
    • requests.get() 메서드로 페이지 번호를 url 에 추가하여 해당 url에서 데이터에 대한 요청 보냄 >> req 에 저장
    • pd.read_html() 메서드로 응답의 html 내용을 읽고 DataFrame의 리스트로 파싱
      • ignore_index=True 매개변수는 각 반복 후 DataFrame의 인덱스를 재설정하여 중복 인덱스 값을 방지
    • pd.concat() 를 사용하여 df 에 새로 가져온 데이터프레임을 이어붙임
    • if count > 10 : break 라는 조건은 10번의 반복(즉, 10개의 페이지) 이후에 크롤링을 중단
    • 반복 루프 이후, df.dropna() 를 통해, 데이터프레임에서 결측치가 포함된 행 제거
    • reset_index 를 사용하여, 인덱스를 새로운 연속적 정수 인덱스로 재설정
    • 최종 데이터 프레임을 return
def getData(url, com_code, soup, page):
    df = None
    count = 0
    for page in range(1, page + 1):
      headers = { 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36' }
      req = requests.get(f'{url}&page={page}', headers=headers)
      
      # 테이블이 있는  html은 매우 다행스럽게도 매우 쉽게 접근이 가능하다.
      # read_html 메서드를 활용한다.
      df = pd.concat([df, pd.read_html(req.text, encoding = "euc-kr")[0]], ignore_index=True)
      if count > 10:
        break
      count += 1
    data = df.dropna().reset_index(drop=True)
    return data

 

🔎 crawler()

  • url 에 회사코드를 추가하여 최종 url 을 만든다.
  • UserAgent 객체를 생성하여 브라우저 정보를 지정한다.
  • 생성한 최종 url로 HTTP GET 요청을 보내고 >> response에 저장
  • 요청에 대해 응답 받은 HTML 내용을 BeautifulSoup으로 파싱
  • 생성한 URL과 파싱한 soup 객체를 return
def crawler(url, com_code):
  url = url + com_code
  ua = UserAgent()
  headers = { 'user-agent': ua.ie }
  response = requests.get(url, headers=headers)
  soup = BeautifulSoup(response.content, "html.parser")
  return url, soup

 

🔎 getLastPage()

  • 이 함수는 soup 에서 마지막 페이지 번호를 추출하는 과정이다.
  • 마지막 페이지에 대한 html 코드를 확인하면 다음과 같다 

  • 마지막 페이지 번호를 찾기 위해 
    • td.pgRR 선택자를 찾고, a['href'] 속성을 가져와, = 를 기준으로 분할하고, 마지막 부분만 떼어냄 >> 이를 last_page 객체에 저장 (여기서는 681이 마지막 페이지인 것으로 보인다.)
    • 추출한 last_page를 return
def getLastPage(soup):
  # 여기가 핵심 포인트
  last_page = int(soup.select_one('td.pgRR').a['href'].split('=')[-1])
  return last_page

 

🔎 main()

  • 지금까지 만든 함수를 종합하여 main 함수를 작성한다.
  • 기준이되는 종목코드 없는 url을 지정
  • 데이터를 가지고 오고 싶은 종목코드 번호를 com_code 에 지정
  • 앞서 지정한 url 과 com_code를 crawler 함수에 넣어, com_url 과 soup를 return
    • 종목코드에 해당하는 회사의 일별 시세가 soup에 담겨있음!
  • getLastPage 함수로 soup에 담긴 데이터가 몇 페이지까지 있는지 확인
    • last_page 값 return
  • result 에 getData 함수를 적용 : 결과를 result에 저장하여 print!
    • url 에는 com_url (crawler함수의 리턴값에 포함되어 있음)
    • com_code 에는 main 에 지정된 종목코드
    • soup : (crawler함수의 리턴값에 포함되어 있음)
    • page 에는 last_page
def main():
    url = "https://finance.naver.com/item/sise_day.nhn?code="
    com_code = '005930' # 삼성전자 다른 종목을 이용할 때 활용
    com_url, soup = crawler(url, com_code)
    last_page = getLastPage(soup)
    result = getData(com_url, com_code, soup, last_page)
    print(result)

if __name__ == "__main__":
    main()
728x90