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
- 깃헙 https://github.com/financedata-org/FinanceDataReader
- 안내서 https://financedata.github.io/posts/finance-data-reader-users-guide.html
- Pandas-datareader https://pandas-datareader.readthedocs.io/en/latest/readers/index.html
- 파이낸스데이터리더는 판다스데이터리더를 대체하기 보다는 보완.
- 06번 강의자료 : 데이터수집은 크롤링보다는 스크래핑에 가깝다.
- GET 방식 : ? 뒤에는 parameter
- POST 방식 : 검색어를 넣었을 때, 텍스트가 인코딩으로 변환해서 넘겨야 한다.
- HTTP 상태 코드를 통해 무슨 방식인지 알 수 있다.
라이브러리 불러오기
- 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 가져오기
- item_code = "" / item_name = "" / page_no = 1
- 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} 바꿔준다.
수집하기
- 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()
여기서는 결측치가 없어서 안해도 된다.
연관기사가 들어가는 데이터 제거
- 얕은 복사
- s1 = pd.Series([1, 2, 3, 4])
s2 = s1 - s2[1] = "a" 로 바꿔줬을 때, s1을 실행해보면 마찬가지로 a로 값이 변경되어 있다.
- 깊은 복사
- s1 = pd.Series([1, 2, 3, 4])
s2 = s1.copy() - 얕은 복사를 하면 원본의 값이 바뀌지만, 깊은 복사하면 원본의 값이 바뀌지 않는다.
- 인덱스 번호를 새로 매겨준다. .reset_index()
- dr_news = df_news.reset_index(drop=True)
- drop=True 안하면 index 칼럼이 생겨서 나오게 된다. 그 칼럼을 없애주기 위해서 drop=True를 써준다.
- 연관기사 제거
- df_news = df_news[~df_news["정보제공"].str.contains("연관기사")].copy()
- 정보제공 칼럼의 연관기사가 들어있지 않은 정보만 보여준다.
- 앞에 ~ 표시하면 True, False 값이 반대로 표현된다.
- 앞에 ~ 표시를 안넣었으면 연관기사가 들어있는 정보만 보여줬을 것.
- ~는 비트와이즈 연산이라고 한다.
- 중복제거
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임.
해결 과제
- 데이터프레임을 다시 출력했을 때 새로 생긴 unnamed0이란 칼럼을 없애는 것을 어디서 배웠는지 찾아보기
- cols=df.columns 를 내가 생각해내서 쓸 수 있을까?
- for문의 변수 설정은 늘 너무 어렵다. news.columns = cols 이 부분 코딩은 for문 할 때 매번 틀린다.
댓글