본문 바로가기
멋쟁이사자처럼 AI스쿨

멋쟁이사자처럼 4주차 회고

by 헬푸밍 2023. 1. 12.

이번 주는 기본적인 데이터 수집에 대해 배웠다.

 

데이터를 수집하면서 많은 어려움이 있었지만...

 

무사히 수업을 마쳤다는 것에... 뿌듯하다!


가장 먼저 실습한 데이터 수집은...

 

FinanceDataReader라이브러리를 통한 금융데이터 수집을 해봤다.

 

FinanceDataReader

- 한국 주식 가격, 미국주식 가격, 지수, 환율, 암호화폐 가격, 종목 리스팅 등 금융 데이터 수집 라이브러리

 

FinanceDataReaderd의 참고자료들...

    -FinanceData/FinanceDataReader: Financial data reader

 

GitHub - financedata-org/FinanceDataReader: Financial data reader

Financial data reader. Contribute to financedata-org/FinanceDataReader development by creating an account on GitHub.

github.com

    - FinanceDataReader 사용자 안내서 | FinanceData

 

FinanceDataReader 사용자 안내서

FinanceDataReader 사용자 안내서

financedata.github.io

    - https://pandas-datareader.readthedocs.io/en/latest/readers/index.html

 

Data Readers — pandas-datareader 0.10.0 documentation

 

pandas-datareader.readthedocs.io

 

설치법

 

아래의 코드로 설치하면...

!pip install -U finance-datareader

다음과 같이 설치가 완료된다.

 

다음으로는 라이브러리를 import하고... 버전을 확인해 보자!

import FinanceDataReader as fdr
fdr.__version__

이렇게 fdr._version__으로 확인한다!

버전을 확인했으면...

 

한번 라이브러리를 사용하지 않고

 

한국거래소 상장종목 전체를 가져와보자!

 

아래와 같은 코드로 데이터를 가져온다.(코드가 꽤 긴 것을 볼 수 있다.)

import pandas as pd # pandas import

url = 'http://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13'
df_listing = pd.read_html(url, header=0, flavor='bs4', encoding='EUC-KR')[0]
# 데이터를 가져오는 코드
cols_ren = {'회사명':'Name', '종목코드':'Symbol', '업종':'Sector', '주요제품':'Industry', 
                    '상장일':'ListingDate', '결산월':'SettleMonth',  '대표자명':'Representative', 
                    '홈페이지':'HomePage', '지역':'Region', }
df_listing = df_listing.rename(columns = cols_ren)
# 컬럼네임을 한글에서 영어로 바꿔주는 코드
df_listing

위처럼 총 2569개의 종목이 가져와진 것을 확인할 수 있다!

 

BUT...

 

라이브러리를 이용하면 단 한줄의 코드를 더 가공된 형태로 데이터를 불러올 수 있다!

df = fdr.StockListing('KRX')
df

한줄의 코드로 위와 같은 결과가 나왔다.

 

이제 이 데이터를 csv파일로 저장하고 다시 불러오면...

df.to_csv('stocklisting.csv', index = False)
df_read = pd.read_csv('stocklisting.csv')
df_read

이렇게 파일이 생기고...

아까 저장했던 데이터가 불러와진다!


다음으로 배운 것은

https://finance.naver.com/item/news.naver?code=005930 

 

네이버 증권

국내 해외 증시 지수, 시장지표, 뉴스, 증권사 리서치 등 제공

finance.naver.com

위의 페이지 기사데이터를 판다스로 수집해보는 것이다.

 

pd.read_html()을 사용해 불러오는 것인데...

pd.read_html()은 HTML의 모든 table을 가져와 리스트 형태로 반환하며

반환된 리스트를 인덱싱하면 데이터프레임으로 데이터를 가져올 수 있다!

pd.read_html(url)과 같은 형식으로 사용한다!

 

아래와 같은 코드로 일단 페이지의 테이블을 가져와보자!

import pandas as pd

url = 'https://finance.naver.com/item/news.naver?code=005930'
temp_table = pd.read_html(url, encoding='cp949')
temp_table

위 처럼 테이블들이 리스트 형태로 가져와진다!

 

그럼 테이블을 인덱스해서 아래의 코드로 테이블 중 하나만 출력해보면...

import pandas as pd
url = 'https://finance.naver.com/item/news.naver?code=005930'

temp_table = pd.read_html(url, encoding='cp949')
temp_table[1]

이렇게 데이터프레임 형태로 반환할 수 있다.

 

이번엔 뉴스기사 수집을 해보자!

먼저, 위 페이지에서 이렇게 뉴스기사 위에 마우스를 올려놓고...

마우스 오른쪽 버튼 클릭 후 검사를 클릭한다!

 

그 후  검사 페이지에서...

순서대로

1. 네트워크

2. 문서

3. 페이지 바꾸는 번호

4. 순서 바꾸면 등장하는 부분의 이름

을 클릭하면...

 

아래와 같이 나오는데...

여기서 요청URL을 복사 후 

웹의 주소창에 복붙해서 들어간다!

 

그러면 아래와 같이 뉴스기사만 있는 창이 나오게 된다!

이제 여기서 데이터 수집을 하는데...

 

주식 종목별, 페이지별 데이터 수집을 하고 싶어서 url을 살펴보자!

 

https://finance.naver.com/item/news_news.naver?code=005930&page=2&sm=title_entity_id.basic&clusterId=

 

URL의 밑줄친 부분이 각각 종목코드와 페이지임을 알 수 있으므로...

변수로 만들어줘서 URL을 조정해 보자!

item_code = "373220"
item_name = "LG에너지솔루션"
page_no = 1

url = f'https://finance.naver.com/item/news_news.nhn?code={item_code}&page={page_no}'

url을 f스트링으로 변수를 넣어줘서 위와 같이 만들어주었다.

일단 종목은 LG에너지솔루션으로 해줬다!

 

이제 기사 테이블을 수집해 보면...

table = pd.read_html(url, encoding = 'cp949')
table

이렇게 리스트 형식으로 나오고...

리스트의 마지막 인덱스는 페이지번호가 담겨있는, 기사와 상관없는 데이터임을 알 수 있다.

 

이제 기사를 데이터프레임으로 만들기 위해...

 

컬럼이름을 지정하고...

리스트안에 있는 데이터프레임들을 모아서...

하나의 데이터프레임으로 합치면...

cols = table[0].columns
cols

temp_list = []
for news in table[:-1]: # 맨마지막 데이터프레임은 페이징 테이블이기 때문에 제외하고 가져옴
    news.columns = cols
    temp_list.append(news)

df_one_page = pd.concat(temp_list)
df_one_page

위와 같이 하나의 데이터프레임으로 반환된다!

 

다음으로는 결측치제거, 연관기사삭제를 진행해보자!

df = df_one_page.dropna()
df = df[~df['제목'].str.contains('연관기사')]
df

아래처럼 더욱 가공된 데이터를 만들었다.

이제 위 과정을 함수로 만들어서

원하는 종목, 원하는 페이지를 수집할 수 있게 해보자!

 

먼저 페이지 url을 얻는 함수를 만들어보면...

def get_url(item_code, page_no):
    """
    item_code, page_no 를 넘기면 url 을 반환하는 함수
    """
    url = f'https://finance.naver.com/item/news_news.nhn?code={item_code}&page={page_no}'
    return url

get_url('005930', 3)

위와 같고, 삼성전자의 3페이지의 url을 수집해봤더니...

이렇게 잘 수집이 된다!

 

이제 뉴스 한 페이지를 수집하는 함수를...

url을 얻는 함수를 이용해 만들어보면...

# get_one_page_news 함수 만들기
def get_one_page_news(item_code, page_no):
    """
    get_url 에 item_code, page_no 를 넘겨 url 을 받아오고
    뉴스 한 페이지를 수집하는 함수
    1) URL 을 받아옴
    2) read_html 로 테이블 정보를 받아옴
    3) 데이터프레임 컬럼명을 ["제목", "정보제공", "날짜"]로 변경
    4) temp_list 에 데이터프레임을 추가
    5) concat 으로 리스트 병합하여 하나의 데이터프레임으로 만들기
    6) 결측치 제거
    7) 연관기사 제거
    8) 중복데이터 제거
    9) 데이터프레임 반환
    """
    news_url = get_url(item_code, page_no)
    temp_table = pd.read_html(news_url, encoding = 'cp949')
    tmp_list = []
    for tmp in temp_table[:-1]:
        tmp.columns = temp_table[0].columns
        tmp_list.append(tmp)
    df_one = pd.concat(tmp_list)
    df_one = df_one.dropna()
    df_one = df_one[~df_one['제목'].str.contains('연관기사')]
    df_one = df_one.drop_duplicates()
    return df_one

위처럼 만들 수 있고

 

카카오의 1페이지 데이터를 수집해보면...

item_code = '035720'
item_name = '카카오'
page_no = 1

temp = get_one_page_news(item_code, page_no)
temp

카카오의 1페이지 기사들이 수집된다.

 

그 다음으로...

반복문을 사용해 10페이지까지 카카오의 기사를 수집해서...

데이터 프레임으로 합치고

인덱스를 리셋하면...

import time
from tqdm import trange #실행과정을 보여주려고 trange import

page_no = 10
news_list = []

for i in trange(page_no):
    news_list.append(get_one_page_news('035720', i+1))
    time.sleep(0.1)

df_news = pd.concat(news_list)
df_news = df_news.reset_index(drop = True)
df_news

위와같이 깨끗하게 수집이 된다!

 

파일로 저장하고 다시 불러오기는 생략...ㅎㅎ

 

여기까지 네이버 증권의 종목별 주식을 원하는 페이지까지 수집해봤습니다!

 

저는 위와 유사한 데이터 수집 연습을 해봤으니 참고로 남길게여...

2023.01.10 - [재미로 하는 코딩] - 네이버 웹 스크래핑 해보기

 

네이버 웹 스크래핑 해보기

오늘은 네이버 웹툰의 베스트도전 페이지를 웹 스크래핑 해보기로 결정했습니다... 왜냐면...? 수업 실습 내용이랑 비슷하기 때문이쥬...ㅋㅋㅋ 일단 네이버 베스트도전 url은 아래와 같습니다...

helpming.tistory.com


마지막으로는....

 

네이버 금융 개별종목 시세 수집을 했다.

 

수집할 페이지의 구성은 대충 이런데...

빨간색 안의 부분을 수집해보려고 한다!

 

기본적인 순서는 이렇다...

  1. 수집 하고자 하는 페이지의 URL을 알아본다.
  2. 파이썬의 작은 브라우저 requests 를 통해 URL에 접근한다.
  3. response.status_code 가 200 OK 라면 정상 응답이다.
  4. request의 response 값에서 response.text 만 받아온다.
  5. html 텍스트를 받아왔다면 BeautifulSoup 로 html 을 해석한다.
  6. soup.select 를 통해 원하는 태그에 접근한다.
  7. 목록을 먼저 받아온다.
  8. 목록에서 행을 하나씩 가져온다.
  9. 행을 모아서 데이터프레임으로 만든다. => 판다스라면 read_html로 table로 된 태그에 대해 위 과정을 코드 한 줄로 해준다.

 

그럼 일단...

라이브러리랑 수집할 데이터 url을 작성하자!

삼성전자의 데이터를 뽑아오기로 했다!

import pandas as pd

item_code = "005930"
item_name = "삼성전자"
page_no = 1

url = f"https://finance.naver.com/item/sise_day.naver?"
url = f"{url}code={item_code}&page={page_no}"

이렇게 작성하고...

pd.read_html()로 테이블을 뽑아보면...

pd.read_html(url)

이렇게 오류가 난다.

 

해결하기 위해 

requests로 http를 요청한다!

페이지 검사를 통해 잘 살펴보면...

요청 메서드가 get인것을 확인한다!

 

코드를 작성해서 상태를 보면

import requests

response = requests.get(url)
response.status_code

이렇게 성공적이나...

response.text

텍스트를 불러오면...

이렇게 페이지를 찾을 수 없다...

 

그래서 다시 검사창에 가서

user_agent를 확인한 뒤

헤더를 지정해줘야 한다!

headers = {'user-agent' : 'Mozilla/5.0'}
response = requests.get(url, headers = headers)
response.text

이렇게 헤더를 추가해주면...

텍스트가 잘 나온 것을 확인할 수 있다.

 

아래의 코드와 같이 테이블만 읽어오면...

table = pd.read_html(response.text)
table

이렇게 출력이 되고...

첫번째 인덱스가 원하고자 하는 데이터프레임을 알 수 있다.

 

table = pd.read_html(response.text)
table
table[0]

이렇게 인덱싱해서

원하는 데이터프레임이 나왔다.

 

temp = table[0].dropna()
temp

이렇게 결측치를 제거해주면..

좀 더 깨끗하다!

 

코드를 합쳐서...

종목별, 페이지별 데이터 수집 함수를 만들면...

def get_day_list(item_code, page_no):
    """
    일자별 시세를 페이지별로 수집
    """
    url = f"https://finance.naver.com/item/sise_day.naver?"
    url = f"{url}code={item_code}&page={page_no}"
    headers = {'user-agent' : 'Mozilla/5.0'}
    response = requests.get(url, headers = headers)
    table = pd.read_html(response.text)
    temp = table[0].dropna()
    return temp

이렇다!

 

이제 반복문으로 2022년 7월 1일 이후의 데이터만 뽑아오는 함수를 만들어서...

데이터프레임을 뽑아보면..

import time

page_no = 1
item_list = []

while True:
    df_day = get_day_list(item_code, page_no)
    item_list.append(df_day)
    first_day = df_day.iloc[-1, 0]
    if first_day <= '2022.07.01':
        break
    time.sleep(0.01)
    page_no += 1
    
df = pd.concat(item_list)
df = df[df['날짜'] >= '2022.07.01']
df

이렇게 7월 1일 이후의 시세만 나오게 된다!

 

다음 코드로 종목코드, 종목명을 추가하고...

컬럼순서를 바꿔주고...

중복값 제거해주고...

인덱스도 리셋해주면!

df['종목코드'] = item_code
df['종목명'] = item_name
cols = ['종목코드', '종목명', '날짜', '종가', '전일비', '시가', '고가', '저가', '거래량']
df = df[cols]
df.drop_duplicates()
df = df.reset_index(drop = True)
df

 

이쁘게 나온다!

 

마지막으로...

최근 날짜를 구해서 종목명, 종목코드, 날짜를 이름으로하는 csv파일을 만들고...

파일로 저장하면...

date = df.iloc[0]['날짜']
file_name = f'{item_name}-{item_code}-{date}.csv'
df.to_csv(file_name, index=False)

이렇게 최근 날짜로 저장이 된다.

 

다시 불러와보자!

pd.read_csv(file_name)

잘불러와진다.

 

이제 페이지별로 일자별 시세를 수집하는 함수만 빼고..

전체 과정을 하나의 함수로 만들고 결과를 보면!

import time

def get_item_list(item_code, item_name):
    """
    일별 시세를 수집하는 함수
    """

    page_no = 1
    item_list = []
    while True:
        df_day = get_day_list(item_code, page_no)
        item_list.append(df_day)
        first_day = df_day.iloc[-1, 0]
        if first_day <= '2022.07.01':
            break
        time.sleep(0.01)
        page_no += 1
    df = pd.concat(item_list)
    df = df[df['날짜'] >= '2022.07.01']
    df['종목코드'] = item_code
    df['종목명'] = item_name
    cols = ['종목코드', '종목명', '날짜', '종가', '전일비', '시가', '고가', '저가', '거래량']
    df = df[cols]
    df.drop_duplicates()
    date = df.iloc[0]['날짜']
    file_name = f'{item_name}-{item_code}-{date}.csv'
    df.to_csv(file_name, index=False)
    return pd.read_csv(file_name)

item_code = "005930"
item_name = "삼성전자"
get_item_list(item_code, item_name)

이렇게 잘 나온다!

 

여기까지 종목별, 페이지별, 일자별 시세 알아보기였네여...


이번주가 엄청 힘들고 벅찼지만 막상 정리하다보니....

 

엄청나게 많이 배운것은 아니라는 생각이 듭니다...

 

모두 금요일 잘 보내시고 행복한 주말보내세요!

댓글