본문 바로가기
부트캠프(LIKELION AIS7)/수업

[AI스쿨 7기, 2주차] 데이터수집(1) - FinanceDataReader, web scraping

by aimaimee 2023. 4. 11.

220927 ( 크롤링, 스크래핑, GET, POST, HTTP, fdr, index=False, time.sleep(), html, F12, charset, concat, dropna, 얕은 복사, 깊은 복사, drop_duplicates(), get_url함수, get_one_page_news 함수 등)

멋쟁이 사자처럼 AI스쿨 7기, 박조은 강사님 강의

✅ 0201 강의 파일

FinanceDataReader

라이브러리 불러오기

  • FinanceDataReader라는 추상화된 도구를 먼저 사용해본다.
  • import FinanceDataReader as fdr
  • 버전 확인은 fdr.version
  • 한국거래서 상장 종목 전체 가져오기 : df=fdr.StockListing("KRX")
  • df.shape : 7890개의 종목
  • df.info() : Q. sector부터 Region까지 왜 결측치가 많을까? 금융상품이라서
  • 도메인 지식이 있다면 무슨 뜻인지 바로 이해할 수 있다.
  • Q. 우리가 불러온 데이터는 어디에 있을까? 메모리
  • 기술통계값 요약 df.describe()했는데 오늘 상장한 데이터가 궁금하니까 찾아본다. df.sort_values(by="ListingDate", ascending=False.head()

파일로 저장하고 불러오기

  • df.to_csv("krx.csv", index=False, encoding="cp949")
  • 한글 등에서 보고 싶으면 cp949
  • 저장된 파일을 데이터프레임으로 읽기 : pd.read_csv("krx.csv", encoding="cp949"
  • unnamed0을 빼고 저장하고 싶을 때 index=False
  • 인코딩 오류가 나면, 불러올 때도 인코딩 지정을 해주면 해결된다.
  • pd.read_html(url)[0] : [0]이 없으면 []안에 데이터가 들어가게 되는데, list에서 indexing을 통해서 데이터를 꺼내기 위해서이다.

✅ 0202 강의 파일

판다스만으로 데이터 수집

데이터 수집 시 유의 사항 : 로봇배제표준. time.sleep()

  • html 구조 이해
  • 마우스 오른쪽, 검사(inspect) : 소스 코드 있는 페이지 볼 수 있다.
  • 어떤 식으로 태그를 접근할 것인지는 뷰티풀수프하면서 다시 해볼 것.
  • table 태그 형태로 되어 있다면 판다스에서 바로 불러올 수 있다.
  • charset : characterset : 인코딩 방식

수집할 url 가져오기

  1. item_code = "" / item_name = "" / page_no = 1
  2. url
    url = f"https://finance.naver.com/item/news_news.nhn?code={item_code}&page={page_no}&sm=title_entity_id.basic&clusterId="
  • {item_code}와 {page_no} 바꿔준다.

수집하기

  1. read_html
    read_html로 수집해서 table이라는 변수에 담는다.
    read_html 출력하면 [] 안에 데이터가 있는 리스트 형식으로 나온다.
    table = pd.read_html(url)
    len(table)
  • 5개라는 출력결과가 나온다. read_html(url) 했을 때 나오는 테이블 갯수를 세는 것이 len(table)

데이터 프레임으로 만들기

  • table의 0번째 인덱스 값을 df라는 변수에 담는다.
  • df = table[0]
  • table[0] 등으로 숫자 바꾸면서 찾아보면 뉴스의 데이터프레임이 나뉘어져 있다는 것을 알 수 있다.
  • 연관기사도 테이블이 되어 있기 때문에 전처리 해줄 필요가 있겠다.
  • cols = df.columns
    cols
  • cols를, 컬럼명을 제목, 정보제공, 날짜로 일치하게 만들어주기 위해 넣어줌

for문으로 데이터 모두 가져오기

temp_list에 수집한 값을 담기

temp_list = []
# 슬라이싱해서 페이지를 클릭하는 마지막 테이블을 제거
for news in table[:-1] :
# news.columns는 밑에 0 1 2 로 되어 있던 칼럼들을 제목, 정보제공, 날짜로 바꿔준다.
news.columns = cols
temp_list.append(news)
display(news)
# 프린트 구문보다 display가 데이터프레임이 보기 좋게 출력된다.

하나의 데이터프레임으로 합치기 concat()

  • df_news = pd.concat(temp_list)
    df_news
  • 출력 결과에서 데이터 중 연관기사는 제거해주어야 한다.

결측치 제거. dropna()

df_news = df_news.dropna()
여기서는 결측치가 없어서 안해도 된다.

연관기사가 들어가는 데이터 제거

  1. 얕은 복사
  • s1 = pd.Series([1, 2, 3, 4])
    s2 = s1
  • s2[1] = "a" 로 바꿔줬을 때, s1을 실행해보면 마찬가지로 a로 값이 변경되어 있다.
  1. 깊은 복사
  • s1 = pd.Series([1, 2, 3, 4])
    s2 = s1.copy()
  • 얕은 복사를 하면 원본의 값이 바뀌지만, 깊은 복사하면 원본의 값이 바뀌지 않는다.
  1. 인덱스 번호를 새로 매겨준다. .reset_index()
  • dr_news = df_news.reset_index(drop=True)
  • drop=True 안하면 index 칼럼이 생겨서 나오게 된다. 그 칼럼을 없애주기 위해서 drop=True를 써준다.
  1. 연관기사 제거
  • df_news = df_news[~df_news["정보제공"].str.contains("연관기사")].copy()
  • 정보제공 칼럼의 연관기사가 들어있지 않은 정보만 보여준다.
  • 앞에 ~ 표시하면 True, False 값이 반대로 표현된다.
  • 앞에 ~ 표시를 안넣었으면 연관기사가 들어있는 정보만 보여줬을 것.
  • ~는 비트와이즈 연산이라고 한다.
  1. 중복제거
    df_news.drop_duplicates()
    중복된 값이 있다면 그 중 하나만 남겨서 보여준다.

함수로 만들어주기

def get_url(item_code, page_no) :
    url = f"https://finance.naver.com/item/news_news.nhn?code={item_code}&page={page_no}&sm=title_entity_id.basic&clusterId="

    return url

# 잘 바뀌는 지 확인하는 과정
item_code = "000660"
page_no = 5
temp_url = get_url(item_code, page_no)
print(temp_url)

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

def get_one_page_news(item_code, page_no):
    url = f"https://finance.naver.com/item/news_news.nhn?code={item_code}&page={page_no}&sm=title_entity_id.basic&clusterId="

    table = read_html(url)
    df = table(0)
    cols = df.columns

    temp_list = []
    for news in table[:-1] :
        news.columns = cols
        temp_list.append(news)

    df_news = pd.concat(temp_list) # 하나의 데이터프레임으로 합쳐줌
    df_news = df_news.dropna() # 결측치 제거
    df_news = df_news.reset_index(drop=True)
    df_news = df_news[~df_news["정보제공"].str.contains("연관기사")].copy()
    df_news.drop_duplcateds()

    return df_news

item code = "000660"
page_no = 2
get_one_page_news(item_code, page_no)

퀴즈

19/20문제

틀린 것

  • 4번문제. 판다스의 describe 기능을 통해 범주형 변수의 기술 통계값을 구했을 때 알 수 없는 것: count, top(최빈값), freq(최빈값에 대한 빈도수)는 구할 수 있지만, mean은 구할 수 없다. mean은 수치형데이터에서만

맞았지만 애매한 것

  • 1번문제. 변수의 유일값(중복을 제외한 unique 값)의 갯수를 구하는 기능 : nunique()
  • 2번문제. 판다스에서 두개 변수에 대한 빈도수를 구할 수 없는 것 : pivot() / 크로스탭, 그룹방, 피봇테이블은 가능
  • 3번문제. 판다스에서 한 개 변수에 대한 빈도수 구하는 것 : value_counts()
  • 17번문제. 수집한 데이터프레임을 df라는 변수에 담았다. csv 파일로 저장할 때 인덱스 값은 제외하고 저장. df.to_csv(file_name, index=False) / pd.to_csv아님. index=False임.

해결 과제

  1. 데이터프레임을 다시 출력했을 때 새로 생긴 unnamed0이란 칼럼을 없애는 것을 어디서 배웠는지 찾아보기
  2. cols=df.columns 를 내가 생각해내서 쓸 수 있을까?
  3. for문의 변수 설정은 늘 너무 어렵다. news.columns = cols 이 부분 코딩은 for문 할 때 매번 틀린다.

댓글