이번 주는 기본적인 데이터 수집에 대해 배웠다.
데이터를 수집하면서 많은 어려움이 있었지만...
무사히 수업을 마쳤다는 것에... 뿌듯하다!
가장 먼저 실습한 데이터 수집은...
FinanceDataReader라이브러리를 통한 금융데이터 수집을 해봤다.
FinanceDataReader
- 한국 주식 가격, 미국주식 가격, 지수, 환율, 암호화폐 가격, 종목 리스팅 등 금융 데이터 수집 라이브러리
FinanceDataReaderd의 참고자료들...
-FinanceData/FinanceDataReader: Financial data reader
- FinanceDataReader 사용자 안내서 | FinanceData
- https://pandas-datareader.readthedocs.io/en/latest/readers/index.html
설치법
아래의 코드로 설치하면...
!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
위의 페이지 기사데이터를 판다스로 수집해보는 것이다.
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을 알아본다.
- 파이썬의 작은 브라우저 requests 를 통해 URL에 접근한다.
- response.status_code 가 200 OK 라면 정상 응답이다.
- request의 response 값에서 response.text 만 받아온다.
- html 텍스트를 받아왔다면 BeautifulSoup 로 html 을 해석한다.
- soup.select 를 통해 원하는 태그에 접근한다.
- 목록을 먼저 받아온다.
- 목록에서 행을 하나씩 가져온다.
- 행을 모아서 데이터프레임으로 만든다. => 판다스라면 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)
이렇게 잘 나온다!
여기까지 종목별, 페이지별, 일자별 시세 알아보기였네여...
이번주가 엄청 힘들고 벅찼지만 막상 정리하다보니....
엄청나게 많이 배운것은 아니라는 생각이 듭니다...
모두 금요일 잘 보내시고 행복한 주말보내세요!
'멋쟁이사자처럼 AI스쿨' 카테고리의 다른 글
네이버 증권 종목토론실수집(과제보충) (0) | 2023.01.18 |
---|---|
네이버 증권 종목토론실수집(과제) (2) | 2023.01.13 |
예외처리(파이썬 강의 Day5) (0) | 2023.01.08 |
모듈과 패키지(파이썬 강의 Day5) (0) | 2023.01.08 |
입력과 출력(파이썬 강의 Day5) (0) | 2023.01.06 |
댓글