지나간 인연을 뒤로하고, 새로운 교수님을 모셨다. 한남대학교 경영정보학과 교수님이 앞으로의 수업을 진행해주신다고 하셨다. 지금까지는 read_csv 함수를 이용하여 기존의 데이터 파일을 불러오는 것이 아닌 웹에서 표시되는 데이터들을 원하는 부분만 긁어오는 것을 크롤링이라고 한다. 크롤링에는 정적 크롤링과 동적 크롤링이 있다. 먼저, 정적 크롤링은 웹 페이지의 HTML 소스코드를 직접 다운로드하여 데이터를 추출하는 방법이다. 이 방법은 서버에서 제공하는 정적인 HTML 컨텐츠만을 대상으로 한다. 동적 크롤링은 JavaScript를 통해 동적으로 생성된 컨텐츠를 수집하는 방법이다. 정적 크롤링이 정적인 데이터를 대상으로 하기 때문에 정적 크롤링을 많이 사용하지만, 동적 크롤링 또한 필요로 의해 여러 곳에서 사용중이다. 이제 자세하게 살펴보자.
1. 데이터 크롤링을 위한 HTML 기초 문법
앞으로 며칠 간 데이터를 크롤링하기 위해 우리는 웹이 어떻게 구성되어 있는지 알아야한다. 인터넷의 대부분의 사이트들은 HTML을 기반으로 구성되어 있다. HTML은 'HyperText Markup Language'의 줄임말이며, 문서가 화면에 표시되는 형식을 나타내거나 데이터의 논리적인 구조를 명시하기 위한 규칙들을 정의한 언어의 일종이다. HTML은 여러 태그들로 이루어져 있다. 태그의 형식은 다음과 같다.
<태그>
...
</태그>
태그를 열고 닫음으로써 원하는 기능을 수행할 수 있도록 한다. 파이썬에서의 괄호와 같이 마지막에는 항상 태그를 통해 닫아주어야 한다. 대표적인 태그들을 살펴보자.
<HEAD> 문서에 대한 전반적인 정보를 표시하는 태그를 포함</HEAD>
<BODY>문서의 내용과 스타일에 대한 태그를 포함</BODY>
<P> 문단을 구분하는 태그</P>
<OL>순서가 있는 목록 태그</OL>
<UL>순서가 없는 목록 태그</UL>
<LI>목록의 요소를 나타내는 태그</LI>
<A>하이퍼링크를 구현하기 위한 태그</A>
<TABLE>문서 내 표를 만들 때 사용하는 태그</TABLE>
<TR>테이블에 행을 삽입하는 태그</TR>
<TD>행 안에 셀을 만들어주는 태그</TD>
<TH>제목 셀을 만드는 태그</TH>
<FORM>사용자가 입력한 정보를 전달하는 태그</FORM>
<SELECT>팝업메뉴, 리스트박스를 사용하기 위한 태그</SELECT>
<TEXTAREA>두줄 이상의 입력을 위한 태그</TEXTAREA>
HTML의 대표적인 태그는 위와 같이 있다. 하지만 위의 태그들만 사용하면 밋밋한 느낌이 들 것이다. 그렇다면 우리가 사용할 수 있는 방법은 CSS를 이용하는 것이다. CSS는 'Cascading Style Sheet'를 의미하며, 글씨의 크기, 색상, 등을 바꿀 수 있도록 해준다. 이 뿐만 아니라, 클래스와 id를 설정하여 태그들의 묶음을 한 번에 지정할 수 있도록 해준다. HTML의 태그들을 살펴보았으니 이제 크롤링을 시작해보자.
2. 라이브러리 연결 및 URL설정
크롤링을 위한 라이브러리들은 다음과 같다.
from urllib.request import urlopen
from bs4 import BeautifulSoup
import pandas as pd
import datetime
from pytz import timezone
import warnings
warnings.filterwarnings('ignore')
6개의 라이브러리를 연결했는데, 이 중 크롤링에 사용되는 라이브러리는 urllib과 BeautifulSoup라이브러리이다. 나머지 모듈들은 앞으로 데이터프레임을 만들거나, 데이터프레임의 열 값으로 사용하기 위해 연결하는 것들이다. 시각화에 대한 라이브러리는 다음 장에서 알아보는 것으로 하자.
data = pd.DataFrame(columns = ['언론사명', '순위', '기사제목', '기사링크', '수집일자'])
먼저 데이터들을 저장할 빈 데이터 프레임을 하나 생성한다. 생성 시 지정해주는 값은 레이블이다.
url = 'https://news.naver.com/main/ranking/popularDay.naver'
크롤링하고자 하는 url을 지정해준다.
html = urlopen(url)
urlopen함수를 사용하여 url에 접속하고, html을 가져온다.
soup = BeautifulSoup(html, 'html.parser')
BeautifulSouf함수를 사용하여 문자들만을 가져온다.
이제 모든 준비는 끝이 났다. 크롤링을 진행하는 코드를 살펴보자.
3. 크롤링을 이용한 데이터 수집
div = soup.find_all('div', {'class':'rankingnews_box'})
# 네이버 랭킹뉴스 기사 제목, 언론사 등 데이터 크롤링
for index_div in range(len(div)):
strong = div[index_div].find('strong', {'class':'rankingnews_name'})
press = strong.text
# 5개 순위 기사 정보 추출
ul = div[index_div].find_all('ul', {'class': 'rankingnews_list'})
for index_r in range(len(ul)):
li = ul[index_r].find_all('li')
for index_l in range(len(li)):
try:
rank = li[index_l].find('em', {'class': 'list_ranking_num'}).text
title = li[index_l].find('a').text
link = li[index_l].find('a').attrs['href']
# 데이터 프레임에 담기
temp_df = pd.DataFrame({'언론사명': press,
'순위':rank,
'기사제목':title,
'기사링크':link,
'수집일자':datetime.datetime.now(timezone('Asia/Seoul'))
}, index = ['순위'])
data = pd.concat([data, temp_df], ignore_index = True)
except:
pass
구조를 살펴보면 3중 반복문이 사용되는 것을 확인할 수 있다. soup 변수에서 'div' 태그를 모두 가져온다. div 태그 중에서 'rankingnew_box'라는 클래스를 가진 태그만을 가져와 div 변수에 저장한다.
find함수와 find_all 함수들을 사용하여 각각의 태그들을 가져오는 것을 확인할 수 있다. 가장 마지막 반복문을 보게 되면 try, except 문을 확인할 수 있다. 이는 예외 처리에 관한 파이썬 문법으로 try 속 코드를 실행시키다 오류가 발생하게 되면 except로 넘어가게 된다. 이렇게 예외처리하는 이유는 값의 수가 정해진 것이 아니기 때문에 중간에 값이 부족하여 발생하는 오류를 넘어가기 위함이다. 마지막으로는 데이터를 데이터 프레임에 삽입하는 과정으로 concat함수를 사용했다.
코드를 실행시킨 후 데이터 프레임을 확인해보면 다음과 같은 결과물을 확인할 수 있다.
이렇게 인기있는 5가지의 뉴스거리를 언론사별로 정리한 데이터프레임을 확인할 수 있게 된다. 그렇다면 위와 같은 결과물을 바탕으로 데이터의 시각화를 진행해보자.
4. 크롤링한 데이터의 시각화
import matplotlib.pyplot as plt
import seaborn as sns
import koreanize_matplotlib
import konlpy
from wordcloud import WordCloud
지금까지 matplotlib과 seaborn 라이브러리는 사용해봤기 때문에 자세한 설명은 지나가도록 하자. matplotlib은 영어를 기준으로 하기 때문에 자칫하면 한글이 깨질 수 있다. 그렇기 때문에 한글을 사용할 수 있는 'koreanize_matplotlib'라이브러리도 함께 연결해주고, konlpy라이브러리는 문자열 속 한글을 분석할 수 있게 해주는 라이브러리이기 때문에 함께 연결해준다. 마지막의 wordcloud 라이브러리는 단어구름을 만들 수 있는 라이브러리이다. 이제 코드와 결과물들을 함께 확인해보자.
text = ' '.join(title for title in data['기사제목'].astype(str))
기사 제목 중 가장 많이 사용되는 단어를 확인하기 위해 기사 제목들을 문자열로 변환한다. 이때 구분자는 띄워쓰는 것으로 지정한다.
font_path = '/content/BMDOHYEON_ttf.ttf'
wc = WordCloud(width = 1000, height = 700, font_path=font_path).generate(text)
plt.axis('off')
plt.imshow(wc, interpolation = 'bilinear')
plt.show()
다음으로는 단어 구름을 생성하는 과정인데, 사용하고자 하는 폰트를 정하고, WordCloud 함수를 사용하여 틀을 잡아준다. 그리고 generate 메서드를 이용하여 text의 내용으로 단어 구름을 생성한다. matplotlib 라이브러리를 사용할 때 표시되는 격자를 없애주고, 출력해주면 된다.
이렇게 하여 사용 빈도가 높은 단어들은 큰 글씨로 다양한 색상을 이용하여 출력할 수 있다. 다음은 사용빈도가 높은 명사를 추출하여 몇 번 사용되었는지 확인하고, 표를 만들어 시각화해보자.
d_text = ' '.join(title for title in data['기사제목'].astype(str))
m_text = ' '.join(title for title in re_data['기사제목'].astype(str))
위의 방법과 같이 기사 제목을 하나의 문자열로 바꿔준다. 이때 d_text 변수는 가장 많이 읽은 뉴스를 담고 있고, m_text 변수는 댓글이 가장 많은 뉴스를 담고 있다.
komoran = konlpy.tag.Komoran()
d_nn = komoran.nouns(d_text)
m_nn = komoran.nouns(m_text)
이제 konlpy라이브러리의 모델을 선택해야한다. 다양한 모델들이 존재하지만, 우리는 Komoran이라는 모델을 사용할 것이다. 해당 모델은 다양한 명사를 구분할 수 있는 기능을 수행한다. komoran을 이용하여 명사들을 추출하여 각각 d_nn, m_nn 변수에 저장한다.
d_word_df = pd.DataFrame({'word':d_nn})
m_word_df = pd.DataFrame({'word':m_nn})
d_word_df = d_word_df.query('count >= 2')
m_word_df = m_word_df.query('count >= 2')
위의 코드를 실행시켜 데이터프레임화 시키고, 2번 이상 사용되는 단어만을 추출하여 데이터의 신뢰성을 높인다. komoran으로 추출한 명사들은 정확도가 떨어지기 때문에 이러한 과정을 거쳐 데이터를 정제한다.
d_group_df = d_word_df.groupby('word', as_index = False).agg(n=('word', 'count')).sort_values('n', ascending = False)
m_group_df = m_word_df.groupby('word', as_index = False).agg(n=('word', 'count')).sort_values('n', ascending = False)
이제 word열에 위치한 단어들끼리 그룹을 만들어준다. sort_values를 통해 내림차순으로 정렬하여 가장 빈도수가 높은 단어가 윗쪽으로 오도록 한다.
fig, axes = plt.subplots(1, 2, figsize = (15, 5))
plt.suptitle('가장 많이 본 뉴스와 댓글이 많은 뉴스의 단어')
sns.barplot(data = d_group_df.head(10), y = 'word', x = 'n', ax = axes[0])
axes[0].set_title('가장 많이 본 뉴스')
sns.barplot(data = m_group_df.head(10), y = 'word', x = 'n', ax = axes[1])
axes[1].set_title('댓글이 가장 많은 뉴스')
plt.show()
이제 비교가 쉽도록 한 캔버스 안에 두개의 표가 들어갈 수 있도록 설정해준 뒤 제목들을 설정해준다.
이렇게 막대그래프 형식을 이용하여 빈도수를 간편하게 확인할 수 있다.
오늘 배운 내용은 여기까지이다. 교수님의 수업 진행 속도가 빨랐지만 머리를 그만큼 많이 써야해서 흥미로운 시간이 되었다.
데이터 분석을 향한 첫 걸음을 내딛은 뒤 처음 진행하는 과정인지라
따라가기 조금 벅찼고, 조원들을 챙기면서 내가 부족했던 점들을 다시 한번
알게 되었다. 더욱 분발해야겠다.
'ABC부트캠프 데이터 탐험가 과정' 카테고리의 다른 글
[13일차] ABC 부트캠프 동적 크롤링 및 시각화 (1) | 2024.07.23 |
---|---|
[12일차] ABC 부트캠프 ESG Day(데이터로 보는 분야) (2) | 2024.07.20 |
[10일차] ABC 부트캠프 파이썬 프로젝트(데이터분석) (0) | 2024.07.17 |
[9일차] ABC 부트캠프 파이썬을 이용한 데이터 처리 심화 (0) | 2024.07.16 |
[8일차] ABC 부트캠프 Pandas를 이용한 데이터 분석 1 (2) | 2024.07.15 |