본문 바로가기
Data Science/Data Science

[Data Science] 파이썬 크롤링 - 워드 클라우드 만들기

by m2162003 2021. 1. 12.

파이썬 모듈을 사용하여 한때 유행했던(?) 워드 클라우드를 만든다.

워드 클라우드란? 워드 클라우드는 텍스트 데이터에서 단어가 등장한 횟수를 기준으로 표현하는 그림이다.

모듈을 사용해서 어려운 점은 딱히 없었지만... 그래도 잊어버리기 쉬우니까 정리해보자.

 

 

1. 영어 문장 나누기

영어 문장에 등장한 단어의 횟수를 세기 위해선 다음 과정을 거친다.

 

1. 특수문자를 지운다.

2. 띄어쓰기를 기준으로 리스트에 단어를 담는다.

3. 등장한 단어의 횟수를 체크한다.

 

 

그리고 위의 과정을 거치기 위해 필요한 모듈은 Counter와 puntucation이다.

Counter는 주어진 리스트에서 특정값이 몇 번 등장하는지 세는 역할

puntuation은 특수문자가 담겨있는 문자열이다.

 

from collections import Counter
from string import punctuation
from text import data 

def count_word_freq(data) :
    
    _data = data.lower() # 전체를 소문자로 바꾼다.
    
    for p in punctuation:
        _data = _data.replace(p, "") # 모든 특수문자를 없앤다.
        
    _data = _data.split() # 공백을 기준으로 나눈다.
        
    counter = Counter(_data) # 등장 횟수를 카운트
    
    print(counter)
    return counter

if __name__ == "__main__" :
    count_word_freq(data)

 

2. 워드클라우드 출력하기

워드 클라우드 모듈이 필요하다. 

from wordcloud import WordCloud

1. 전처리 - 단어 빈도수 얻기

counter = count_word_freq(data)
# 앞서 제작한 함수로 문장 내에 단어의 등장 횟수를 체크하여 딕셔너리 형태로 리턴한다.

 

2 워드 클라우드 객체 생성하기

cloud = WordCloud(background_color='white') # 워드 클라우드 객체 생성

 

3. 단어의 빈도수 얻기

fit_words는 input을 단어들의 빈도수가 담긴 딕셔너리를 받아서 워드 클라우드를 생성한다.

cloud.fit_words(counter)

 

3. 한글 워크 클라우드 만들기

영어와 다르게 한글은 어미와 조사 때문에 공백으로 단어가 분리되지 않는다....

형태소 별로 구분하기 위한 모듈이 따로 존재한다.

from mecab import MeCab
mecab = MeCab()

text = "광화문역 주변에 있는 맛집을 알고 싶어요. 정보를 얻을 수 있을까요?"

# 1. 형태소 별로 나눠 출력해보기
print(mecab.morphs(text))

# 2. 명사만 출력해보기
print(mecab.nouns(text))

# 3. 형태소 별로 나누고 품사 출력해보기
print(mecab.pos(text))

 

실습2

주로 코딩했던 부분은 크롤링이긴하지만..

create_word_cloud는 워드 클라우드를 생성하는 부분이다.

import requests
from bs4 import BeautifulSoup
from wc import create_word_cloud


#기사의 내용을 하나의 문장으로 반환한다.
def crawling(soup) :
    div = soup.find('div', class_="_article_body_contents")
    
    result = div.get_text().replace('\n', '').replace('// flash 오류를 우회하기 위한 함수 추가function _flash_removeCallback() {}', '').replace('\t', '')
    
    return result
    
    
def get_href(soup, custom_header) :
    result = []
    
    cluster_head = soup.find("h2", class_="cluster_head_topic")
    href = cluster_head.find("a")["href"]
    
    url = "https://news.naver.com" + href
    req = requests.get(url, headers=custom_header)
    new_soup = BeautifulSoup(req.text, "html.parser")
    
    main_content = new_soup.find("div", id="main_content")
    
    for ul in main_content.find_all("ul") :
        for a in ul.find_all("a") :
            result.append(a["href"])
    
    return result


def get_request(section, custom_header) :
    url = "https://news.naver.com/main/main.nhn"
    section_dict = { "정치" : 100,
                     "경제" : 101,
                     "사회" : 102,
                     "생활" : 103,
                     "세계" : 104,
                     "과학" : 105 }
    return requests.get(url, params={"sid1":section_dict[section]}, headers=custom_header)

# 추가된 코드입니다.
def get_href_politics(soup, custom_header) :
    result = []
    cluster_head = soup.find("td", class_="content")
    div = soup.find_all("div", class_="cluster_text")
    for a in div:
        result.append(a.find("a")["href"])
    return result
    
    
def main() :
    custom_header = {'user-agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'}
    list_href = []
    result = []
    
    # 섹션을 입력하세요.
    section = input('"정치", "경제", "사회", "생활", "세계", "과학" 중 하나를 입력하세요.\n  > ')
    
    req = get_request(section, custom_header)
    soup = BeautifulSoup(req.text, "html.parser")
    
    # 추가된 코드입니다.
    if section != "정치":
        list_href = get_href(soup, custom_header)
    else:
        list_href = get_href_politics(soup, custom_header)
    
    for href in list_href :
        href_req = requests.get(href, headers=custom_header)
        href_soup = BeautifulSoup(href_req.text, "html.parser")
        result.append(crawling(href_soup))
    
    text = " ".join(result)
    create_word_cloud(text)
    

if __name__ == "__main__" :
    main()

댓글