내맘대로 뉴스 요약 큐레이션 (1) - 시작 그리고 뉴스 크롤링
내맘대로 사이드 프로젝트는 내맘대로니까 의식의 흐름대로 막씀. 반말로 씀.
0. 내맘대로 뉴스 기사 요약 + 큐레이션 프로젝트 시작.
일요일 오후 1:30분.. 글쓰기 마감일인데, 이번주도 한 글자도 안썼다…
집에서는 안되겠다 싶어 노트북을 챙겨서 빽다방에 나왔다.
이번주는 ~또 어떻게 때우나~ 어떤 글을 써볼까 고민하다가, 사이드 프로젝트 아이디어 리스트에 고이고이 묶혀둔 뉴스 기사 요약 + 큐레이션 프로젝트 를 꺼내기로 했다. (이걸로 한 세개는 써야겠다.)
오래된 주제라 참고해볼 자료도 많고, 써볼 수 있는 방법들도 다양할 것 같아 공부용으로 시작해볼 괜찮은 주제 같아 사이드 프로젝트로 선정해보았다.
최종 결과물이 어떤 형태일 지는 아직 모르겠지만 일단 시작.
1. 데이터 수집: 뉴스 기사를 긁어보자
일단 처음엔 쉽게 접근하기 위해 ~만만한~ 각 언론사별 뉴스 기사들을 잘 제공하고 있는 네이버 뉴스 서비스를 털어보기로 했다.
네이버 뉴스 서비스를 들어가보았다.
일단 모든 뉴스 기사를 수집하기 보다는 첫 시작점으로 오른쪽 란의 가장 많이 본 뉴스 데이터를 수집해보기로 했다.
(1) 긁어올 데이터 뜯어보기
가장 많이 본 뉴스
서비스에서 이것저것 누르다보면 아래와 같이 url 구조를 쉽게 파악할 수 있다.
많이 본 뉴스
- url: https://news.naver.com/main/ranking/popularDay.nhn
- rankingType: 섹션별인 경우 popular_day, 연령 별인 경우 age
- sectionId: 102 (100: 정치, 101: 경제, 102: 사회, 103: 생활/문화, 104: 세계, 105: IT/과학, 003: 포토, 115: TV - 섹션별인 경우 사용가능)
- subType: 30 (10대~60대) (연령 별인 경우 사용가능)
- date: 20200426 (날짜 %Y%m%d)
댓글 많은 뉴스
- url: https://news.naver.com/main/ranking/popularMemo.nhn
- rankingType: popular_memo
- sectionId: 102 (100: 정치, 101: 경제, 102: 사회, 103: 생활/문화, 104: 세계, 105: IT/과학, 003: 포토, 115: TV)
- date: 날짜 (날짜 %Y%m%d)
공감 많은 뉴스
- url: https://news.naver.com/main/ranking/popularLike.nhn
- subType: 30 (10대~60대)
- 날짜별로는 제공하지 않는다.
SNS 공유 많은 뉴스
- url: https://news.naver.com/main/ranking/popularShare.nhn
- 날짜별로는 제공하지 않는다.
많이 본 뉴스
와 댓글 많은 뉴스
의 경우 날짜 별 데이터를 긁어올 수 있었는데, 공감 많은 뉴스
와 SNS 공유 많은 뉴스
는 그렇지 않았다.
SNS 공유 많은 뉴스
의 경우는 남들에게 적극적으로 공유하는 기준이라 좀 더 중요도가 높은 뉴스가 많을 것 같은데 아쉽다.
일단은 많이 본 뉴스
에 대해서 일자별 섹션별로 데이터를 크롤링해보기로 했다.
(2) 긁어올 데이터의 DOM 구조를 살펴본다.
다행히 크게 어렵지 않을 것 같이 생겼다.
ranking_list 별로 ranking_headline, ranking_lede, ranking_office, ranking_view 값들을 가져오면 될 것 같다.
ranking_headline 에는 해당 기사에 대한 링크도 제공하고 있어서 뉴스 내용까지 긁어올 수 있을 것 같다.
(3) 크롤링 코드 작성
(이하 자세한 설명은 생략한다)
from datetime import datetime, timedelta
from selenium import webdriver
from tqdm import tqdm
def get_chrome_driver():
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_driver = webdriver.Chrome('./chromedriver', options=chrome_options)
return chrome_driver
_SECTIONS = {
'100': '정치',
'101': '경제',
'102': '사회',
'103': '생활/문화',
'104': '세계',
'105': 'IT/과학'
}
def get_popular_day_news_contents(date, section_id):
url = f'https://news.naver.com/main/ranking/popularDay.nhn' \
f'?rankingType=popular_day' \
f'§ionId={section_id}&date={date}'
driver.get(url)
driver.implicitly_wait(1)
ranking = driver.find_elements_by_class_name('ranking')
if ranking:
headlines = ranking[0].find_elements_by_class_name('ranking_headline')
ledes = ranking[0].find_elements_by_class_name('ranking_lede')
offices = ranking[0].find_elements_by_class_name('ranking_office')
views = ranking[0].find_elements_by_class_name('ranking_view')
return zip(headlines, ledes, offices, views)
else:
return None
def get_popular_day_news(driver, start_date, end_date):
fp = open(f'./popularDay-{start_date}-{end_date}.tsv', 'w')
columns = ['date', 'section', 'office', 'view', 'headline', 'lede', 'link']
fp.write('\t'.join(columns) + '\n')
target_dates = get_date_strings(start_date, end_date)
for date_str in tqdm(target_dates):
for section_id, section_name in _SECTIONS.items():
contents = get_popular_day_news_contents(date_str, section_id)
if contents:
for headline, lede, office, view in contents:
headline_a_tag = headline.find_element_by_tag_name('a')
contents = '\t'.join([
date_str,
section_name,
office.text,
view.text,
headline_a_tag.get_attribute('title'),
lede.text,
headline_a_tag.get_attribute('href')
])
fp.write(contents + '\n')
driver.quit()
def get_date_strings(start_date, end_date):
date_strings = []
curr = datetime.strptime(start_date, '%Y%m%d')
end = datetime.strptime(end_date, '%Y%m%d')
while True:
if curr > end:
break
else:
date_strings.append(
curr.strftime('%Y%m%d')
)
curr = curr + timedelta(days=1)
return date_strings
if __name__ == '__main__':
driver = get_chrome_driver()
start_date = '20200101'
end_date = '20200131'
date_strings = get_date_strings(start_date, end_date)
print(date_strings)
get_popular_day_news(driver, start_date, end_date)
빠르게 코드를 작성하고 2020년 1월 ~ 2020년 4월
치의 데이터(날짜, 섹션, 언론사, 제목, 내용, 링크, 조회수)를 긁어왔다.
각 뉴스의 전체 내용도 링크를 통해서 쉽게 가져올 수 있을 것 같은데, 귀찮아서 다음 todo로 남겨두었다.
한 세션에서 가능한 요청량이 정해져있기 때문에 한번에 너무 많은 양을 호출하면 안되고 한달치 정도씩만 가져와야한다.
3. 데이터 뜯어보기
(1) 데이터 읽어오기
!ls ~/private/news-crawler
Pipfile popularDay-20200101-20200131.tsv
Pipfile.lock popularDay-20200201-20200229.tsv
chromedriver popularDay-20200301-20200331.tsv
crawler popularDay-20200401-20200426.tsv
import warnings
warnings.filterwarnings(action='ignore')
import pandas as pd
import soynlp
import matplotlib.pyplot as plt
import re
import pyecharts
import matplotlib.font_manager as fm
plt.rc('font', family='NanumGothic')
print(plt.rcParams['font.family'])
['NanumGothic']
- 사실 위 한글폰트 문제로 3시간을 헤맸다…ㅜ
- 한글 폰트를 설치하고 열심히 경로를 지정해주었지만 변화가 없다가 나중에 캐시를 지워주어야 한다는 사실을 깨달았다고 한다.
- matplotlib.get_cachedir() <- 폴더를 날리고 노트북 재시작
dataset_dir = '~/private/news-crawler'
filenames = [
'popularDay-20200101-20200131.tsv',
'popularDay-20200201-20200229.tsv',
'popularDay-20200301-20200331.tsv',
'popularDay-20200401-20200426.tsv'
]
data = pd.concat([
pd.read_csv(f'{dataset_dir}/{f}', sep='\t', error_bad_lines = False, warn_bad_lines=False)
for f in filenames
])
data['datetime'] = pd.to_datetime(data['date'], format='%Y%m%d')
data.head()
date | section | office | view | headline | lede | link | datetime | |
---|---|---|---|---|---|---|---|---|
0 | 20200101 | 정치 | 경향신문 | 130,669 | 박지원 “이낙연 종로 출마하면 황교안 못해···황 불출마? 띄워보기 말고 본인 입으… | 박지원 대안신당(가칭) 의원은 1일 황교안 자유한국당 대표의 4월 총선 불출마설과 … | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 |
1 | 20200101 | 정치 | 서울신문 | 128,362 | 김도읍 불출마… 공수처법 무기력 후폭풍 | [서울신문] 7번째… 與·문의장 협조해야 사퇴 확정 공직선거법 개정안과 고위공직자범… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 |
2 | 20200101 | 정치 | 경향신문 | 104,680 | 유승민 “2년 전 결혼 잘못해 고생했지만···” | 새로운보수당 인재영입위원장을 맡고 있는 바른미래당 유승민 의원은 1일 “2년 전 결… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 |
3 | 20200101 | 정치 | 한겨레 | 81,894 | 민주당 지지율 ‘한국당 2배’…부산·울산·경남도 15%p 높아 | 여당인 더불어민주당이 정당 지지도나 선호도에서 제1야당인 자유한국당을 두배쯤 앞서는… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 |
4 | 20200101 | 정치 | 조선일보 | 76,126 | 새해 첫날 보수대통합 꺼내든 황교안·유승민… “시간이 없다” | ‘보수통합추진위 구성→설 前 통합 원칙 합의→2월초 통합 마무리’ 시나리오 거론 지… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 |
- 데이터 불러오기 성공! 원하는 대로 잘 긁어온 것 같다.
(2) 주요 키워드 추출해보기
어떤 걸 해볼까하다가 뉴스 제목(headline)과 내용(lede)을 기반으로 주요 키워드를 추출해보기로 했다.
뉴스데이터의 경우는 신조어가 많이 등장하는 편인데, 일반 토크나이저를 사용할 경우 신조어는 잘 인식하지 못하여 soynlp 라이브러리를 사용하여 추출하였다.
내용 중 쓸모없는 특수문자 및 19일, 2020년 등의 의미없는 날짜, 연령대 단어, 언론사 명 들은 적절히 전처리해주었다.
from soynlp.utils import DoublespaceLineCorpus
from soynlp.noun import LRNounExtractor_v2
_office_list = list(data.office) + list(o[:-1] for o in data.office)
def prep(sent: str):
prep = re.sub('\W+', ' ', sent)
prep = re.sub(r'\d+일', '', prep)
prep = re.sub(r'\d+년', '', prep)
prep = re.sub(r'\d+대', '', prep)
return prep
def is_office(word):
if word in _office_list:
return True
else:
return False
def get_global_top_keywords(data):
sents = list(data['headline']) + list(data['lede'])
prep_sents = [prep(sent) for sent in sents]
noun_extractor = LRNounExtractor_v2(verbose=True, extract_compound=True)
noun_extractor.train(prep_sents)
nouns = noun_extractor.extract()
top_keywords = []
for n, k in sorted(nouns.items(), key=lambda x: x[1].frequency, reverse=True):
if len(n) >= 3 and k.frequency >= 30 and not is_office(n):
top_keywords.append((n, k.frequency))
return top_keywords
top_keywords = get_global_top_keywords(data)
top_keywords[:50]
[Noun Extractor] use default predictors
[Noun Extractor] num features: pos=3929, neg=2321, common=107
[Noun Extractor] counting eojeols
[EojeolCounter] n eojeol = 99726 from 41598 sents. mem=0.321 Gb
[Noun Extractor] complete eojeol counter -> lr graph
[Noun Extractor] has been trained. #eojeols=543802, mem=0.394 Gb
[Noun Extractor] batch prediction was completed for 26260 words
[Noun Extractor] checked compounds. discovered 8099 compounds
[Noun Extractor] postprocessing detaching_features : 19517 -> 18478
[Noun Extractor] postprocessing ignore_features : 18478 -> 18378
[Noun Extractor] postprocessing ignore_NJ : 18378 -> 18353
[Noun Extractor] 18353 nouns (8099 compounds) with min frequency=1
[Noun Extractor] flushing was done. mem=0.417 Gb
[Noun Extractor] 72.84 % eojeols are covered
[('코로나19', 5487),
('코로나바이러스', 2832),
('코로나', 2648),
('감염증', 2602),
('확진자', 2044),
('마스크', 1726),
('대통령', 1202),
('신천지', 936),
('삼성전자', 898),
('바이러스', 673),
('문재인', 579),
('사망자', 576),
('트럼프', 551),
('스마트폰', 548),
('지난해', 483),
('현지시간', 474),
('한국인', 454),
('청와대', 428),
('아파트', 412),
('네이버', 412),
('황교안', 402),
('미래통합당', 395),
('온라인', 390),
('김정은', 390),
('기생충', 382),
('신종코로나', 334),
('이탈리아', 329),
('더불어민주당', 328),
('WHO', 323),
('민주당', 317),
('가능성', 308),
('윤석열', 298),
('유튜브', 292),
('갤럭시S20', 283),
('자가격리', 282),
('지난달', 279),
('진중권', 278),
('법무부', 275),
('치료제', 274),
('갤럭시', 262),
('안철수', 259),
('자유한국당', 258),
('이만희', 252),
('감염자', 238),
('추미애', 234),
('특파원', 234),
('중국인', 233),
('통합당', 229),
('조주빈', 227),
('봉준호', 226)]
2020년 1월 ~ 4월 간 핫한 키워드는 역시 코로나
다.
중간에 선거가 있어서인지 정치 관련 키워드도 보이고, 기생충, 조주빈 등 한동안 크게 이슈화 됬던 키워드들이 뽑혔다.
(3) 키워드 별 시간별 트렌드 보기
- 주요 키워드 별로 시간대 별 기사 수를 살펴보면 재밌을 것 같아 해당 키워드를 언급한 기사를 표시하고, 날자별로 그래프를 그려보기로 했다.
def get_keywords_from_news(headline, lede, keywords):
news_keywords = list(set([
keyword[0] for keyword in keywords
if keyword[0] in headline or keyword[0] in lede
]))
return ','.join(news_keywords)
data['keywords'] = data.apply(lambda x: get_keywords_from_news(x['headline'], x['lede'], top_keywords), axis=1)
data.head(10)
date | section | office | view | headline | lede | link | datetime | keywords | |
---|---|---|---|---|---|---|---|---|---|
0 | 20200101 | 정치 | 경향신문 | 130,669 | 박지원 “이낙연 종로 출마하면 황교안 못해···황 불출마? 띄워보기 말고 본인 입으… | 박지원 대안신당(가칭) 의원은 1일 황교안 자유한국당 대표의 4월 총선 불출마설과 … | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 | 한국당,황교안,자유한국당,이낙연,불출마 |
1 | 20200101 | 정치 | 서울신문 | 128,362 | 김도읍 불출마… 공수처법 무기력 후폭풍 | [서울신문] 7번째… 與·문의장 협조해야 사퇴 확정 공직선거법 개정안과 고위공직자범… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 | 후폭풍,불출마 |
2 | 20200101 | 정치 | 경향신문 | 104,680 | 유승민 “2년 전 결혼 잘못해 고생했지만···” | 새로운보수당 인재영입위원장을 맡고 있는 바른미래당 유승민 의원은 1일 “2년 전 결… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 | 새로운보수당,위원장,유승민,바른미래,바른미래당 |
3 | 20200101 | 정치 | 한겨레 | 81,894 | 민주당 지지율 ‘한국당 2배’…부산·울산·경남도 15%p 높아 | 여당인 더불어민주당이 정당 지지도나 선호도에서 제1야당인 자유한국당을 두배쯤 앞서는… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 | 더불어민주당이,더불어민주당,민주당,한국당,자유한국당,지지율 |
4 | 20200101 | 정치 | 조선일보 | 76,126 | 새해 첫날 보수대통합 꺼내든 황교안·유승민… “시간이 없다” | ‘보수통합추진위 구성→설 前 통합 원칙 합의→2월초 통합 마무리’ 시나리오 거론 지… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 | 마무리,황교안,유승민,보수통합 |
5 | 20200101 | 정치 | 동아일보 | 74,470 | “공무원증 밥값 결제” 혁신賞 준 정부 | [2020 新목민심서-공직사회 뿌리부터 바꾸자] 혁신안 내랬더니 민원사항 내… 부처… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 | 2020,공무원 |
6 | 20200101 | 정치 | MBC | 73,265 | 김정은 “충격적 실제행동…새 전략무기 목격할 것” | [정오뉴스]◀ 앵커 ▶ 북한이 오늘 김정은 국무위원장의 새해 신년사 대신 어제까지 … | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 | 국무위원장,김정은,위원장 |
7 | 20200101 | 정치 | 연합뉴스 | 69,925 | 유시민 “曺가 풀었단 시험은 온라인 오픈북시험…깜찍한 기소” | 조국 공소장 반박…”노무현재단 계좌 볼 수 있는 모든 기관에 서면질의할 것”유튜브 … | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 | 노무현재단,유시민,유튜브,온라인 |
8 | 20200101 | 정치 | 중앙일보 | 67,268 | 故윤한덕 아들과 아차산 오른 文 “대통령 만난 새해 운수대통” | 문재인 대통령은 경기도에 있는 아차산을 오르는 것으로 2020년 새해를 열었다. 문… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 | 문재인,대통령,경기도,2020 |
9 | 20200101 | 정치 | 연합뉴스 | 66,793 | 文대통령, 아차산서 새해맞이…”국민 행복한 한해, 정부가 앞장”(종합) | 취임 후 세 차례 새해 모두 의인과 등반…하산 후 靑 관저서 떡국 조찬시민들에 “운… | https://news.naver.com/main/ranking/read.nhn?r… | 2020-01-01 | 대통령,시민들,文대통령 |
- keyword 에 잘 표시되었다.
- 동시에 함께 나온 키워드들을 보는 것도 재밌을 듯
전체 데이터셋에서 키워드를 뽑으면 코로나만 너무 많이 나올 것 같아서 월별 TOP 키워드들을 뽑아서 그래프를 그려보기로 했다.
top_keywords1 = get_global_top_keywords(
data[(data['datetime'] >= '20200101') & (data['datetime'] < '20200201')]
)
top_keywords2 = get_global_top_keywords(
data[(data['datetime'] >= '20200201') & (data['datetime'] < '20200301')]
)
top_keywords3 = get_global_top_keywords(
data[(data['datetime'] >= '20200301') & (data['datetime'] < '20200401')]
)
top_keywords4 = get_global_top_keywords(
data[(data['datetime'] >= '20200401') & (data['datetime'] < '20200501')]
)
tops = list(set([
keyword for keyword, _ in
top_keywords1[:20] + top_keywords2[:20] + top_keywords3[:20] + top_keywords4[:20]
]))
tops
[Noun Extractor] use default predictors
[Noun Extractor] num features: pos=3929, neg=2321, common=107
[Noun Extractor] counting eojeols
[EojeolCounter] n eojeol = 40587 from 10948 sents. mem=0.317 Gb
[Noun Extractor] complete eojeol counter -> lr graph
[Noun Extractor] has been trained. #eojeols=144847, mem=0.318 Gb
[Noun Extractor] batch prediction was completed for 11391 words
[Noun Extractor] checked compounds. discovered 1715 compounds
[Noun Extractor] postprocessing detaching_features : 7045 -> 6886
[Noun Extractor] postprocessing ignore_features : 6886 -> 6823
[Noun Extractor] postprocessing ignore_NJ : 6823 -> 6821
[Noun Extractor] 6821 nouns (1715 compounds) with min frequency=1
[Noun Extractor] flushing was done. mem=0.318 Gb
[Noun Extractor] 63.75 % eojeols are covered
[Noun Extractor] use default predictors
[Noun Extractor] num features: pos=3929, neg=2321, common=107
[Noun Extractor] counting eojeols
[EojeolCounter] n eojeol = 34749 from 10344 sents. mem=0.301 Gb
[Noun Extractor] complete eojeol counter -> lr graph
[Noun Extractor] has been trained. #eojeols=134719, mem=0.309 Gb
[Noun Extractor] batch prediction was completed for 9857 words
[Noun Extractor] checked compounds. discovered 1524 compounds
[Noun Extractor] postprocessing detaching_features : 6031 -> 5893
[Noun Extractor] postprocessing ignore_features : 5893 -> 5843
[Noun Extractor] postprocessing ignore_NJ : 5843 -> 5839
[Noun Extractor] 5839 nouns (1524 compounds) with min frequency=1
[Noun Extractor] flushing was done. mem=0.310 Gb
[Noun Extractor] 65.80 % eojeols are covered
[Noun Extractor] use default predictors
[Noun Extractor] num features: pos=3929, neg=2321, common=107
[Noun Extractor] counting eojeols
[EojeolCounter] n eojeol = 38423 from 11028 sents. mem=0.296 Gb
[Noun Extractor] complete eojeol counter -> lr graph
[Noun Extractor] has been trained. #eojeols=143502, mem=0.304 Gb
[Noun Extractor] batch prediction was completed for 10792 words
[Noun Extractor] checked compounds. discovered 1751 compounds
[Noun Extractor] postprocessing detaching_features : 6678 -> 6462
[Noun Extractor] postprocessing ignore_features : 6462 -> 6409
[Noun Extractor] postprocessing ignore_NJ : 6409 -> 6407
[Noun Extractor] 6407 nouns (1751 compounds) with min frequency=1
[Noun Extractor] flushing was done. mem=0.303 Gb
[Noun Extractor] 66.53 % eojeols are covered
[Noun Extractor] use default predictors
[Noun Extractor] num features: pos=3929, neg=2321, common=107
[Noun Extractor] counting eojeols
[EojeolCounter] n eojeol = 35469 from 9278 sents. mem=0.294 Gb
[Noun Extractor] complete eojeol counter -> lr graph
[Noun Extractor] has been trained. #eojeols=120734, mem=0.302 Gb
[Noun Extractor] batch prediction was completed for 10038 words
[Noun Extractor] checked compounds. discovered 1406 compounds
[Noun Extractor] postprocessing detaching_features : 5939 -> 5799
[Noun Extractor] postprocessing ignore_features : 5799 -> 5748
[Noun Extractor] postprocessing ignore_NJ : 5748 -> 5743
[Noun Extractor] 5743 nouns (1406 compounds) with min frequency=1
[Noun Extractor] flushing was done. mem=0.301 Gb
[Noun Extractor] 62.77 % eojeols are covered
['신종코로나',
'확진자',
'이만희',
'크루즈선',
'청와대',
'코로나19',
'우한폐렴',
'지난해',
'기생충',
'한국인',
'긴급재난지원금',
'현지시간',
'자유한국당',
'현지시',
'신천지',
'바이러스',
'윤석열',
'진중권',
'텔레그램',
'삼성전자',
'마스크',
'스마트폰',
'재난지원금',
'추미애',
'법무부',
'온라인',
'문재인',
'대통령',
'더불어민주당',
'조주빈',
'코로나',
'치료제',
'중국인',
'아파트',
'김정은',
'코로나바이러스',
'후베이성',
'네이버',
'이탈리아',
'아카데미',
'한국당',
'봉준호',
'사망자',
'미래통합당',
'통합당',
'감염증',
'트럼프']
def get_keyword_summ(unique_date, data, keyword):
tmp = data.copy()
tmp[f'has_{keyword}'] = tmp.keywords.str.contains(keyword)
keyword_summ = tmp[['date', f'has_{keyword}']][tmp[f'has_{keyword}']].groupby(
['date']
).count().reset_index()
keyword_data = pd.merge(unique_date, keyword_summ, on='date', how='left')
keyword_data = keyword_data.fillna(0)
return keyword_data
unique_date_df = pd.DataFrame(data['date'].unique(), columns=['date'])
plt.figure(figsize=(20, 15))
for keyword in tops:
keyword_data = get_keyword_summ(unique_date_df, data, keyword)
plt.plot(
pd.to_datetime(keyword_data['date'], format='%Y%m%d'),
keyword_data[f'has_{keyword}'],
label=keyword
)
plt.legend(fontsize=10)
- 오 뭔가 의도한 대로 잘 나왔는데 알아보기가 어렵다.
- 주제어 별로 클러스터링이 잘 되어야 좀 보기 편할 것 같다.
아래에서부터는 matplotlib 그래프가 별로 이쁘지 않아서 다른 차트 라이브러리를 사용해보았다. (그런데 노트북 파일에서는 결과가 안보여져서 ㅠ 결국 그냥 이미지를 첨부하였다 ㅠ)
from pyecharts import Line
unique_dates = [str(date) for date in list(keyword_data['date'])]
<코로나 관련="" 트렌드="">코로나>
line = Line()
for keyword in ['코로나', '우한폐렴', '바이러스', '마스크', '신천지', '재난지원금']:
keyword_data = get_keyword_summ(unique_date_df, data, keyword)
line.add(
name=keyword,
x_axis=unique_dates,
y_axis=[int(item) for item in list(keyword_data[f'has_{keyword}'])],
mark_point=['max']
)
# line - notebook 에서 로딩 안됨 ㅠ 아래는 그냥 이미지를 넣음
- 공식 병명이 코로나19로 바뀌면서 우한 폐렴 이라는 워딩은 2월 초 이후로 잘 안쓰이게 되었다. 바이러스는 계속 언급된다.
- 우리나라는 신천지 사태 이후로 확진자가 크게 늘게 되었는데, 그 이후로 확진자가 크게 늘고 마스크 대란이 일어나면서 마스크 키워드가 급등한 걸 볼 수 있다.
- 요즘은 재난지원금에 대한 뉴스가 많아 재난지원금에 대한 뉴스가 많아지고 있는 것도 확인할 수 있다.
<기생충 관련="">기생충>
line = Line()
for keyword in ['기생충', '봉준호']:
keyword_data = get_keyword_summ(unique_date_df, data, keyword)
line.add(
name=keyword,
x_axis=unique_dates,
y_axis=[int(item) for item in list(keyword_data[f'has_{keyword}'])],
mark_point=['max']
)
# line - notebook 에서 로딩 안됨 ㅠ 아래는 그냥 이미지를 넣음
line = Line()
for keyword in ['텔레그램', '조주빈', 'n번방']:
keyword_data = get_keyword_summ(unique_date_df, data, keyword)
line.add(
name=keyword,
x_axis=unique_dates,
y_axis=[int(item) for item in list(keyword_data[f'has_{keyword}'])],
mark_point=['max']
)
# line - notebook 에서 로딩 안됨 ㅠ 아래는 그냥 이미지를 넣음
- 전국민을 분노하게 했던 n번방 사건.
- 박사의 정체가 공개되었을 때 피크점을 찍은 것으로 보인다.
- 점점 기사 수도 줄어들고 관심에서 멀어지는 것 같아서 안타깝다.
<김정은 관련="">김정은>
line = Line()
for keyword in ['김정은']:
keyword_data = get_keyword_summ(unique_date_df, data, keyword)
line.add(
name=keyword,
x_axis=unique_dates,
y_axis=[int(item) for item in list(keyword_data[f'has_{keyword}'])],
mark_point=['max']
)
# line - notebook 에서 로딩 안됨 ㅠ 아래는 그냥 이미지를 넣음
<트럼프 관련="">트럼프>
line = Line()
for keyword in ['트럼프']:
keyword_data = get_keyword_summ(unique_date_df, data, keyword)
line.add(
name=keyword,
x_axis=unique_dates,
y_axis=[int(item) for item in list(keyword_data[f'has_{keyword}'])],
mark_point=['max']
)
# line - notebook 에서 로딩 안됨 ㅠ 아래는 그냥 이미지를 넣음
- 꾸준히 언급되는
트럼프
와 대조적으로 최근김정은
사망설이 뜨면서 김정은 키워드가 크게 이슈화 되고 있는 것을 볼 수 있다. - 전쟁나면 안됨..
4. To do
일단 이번주 차는 뉴스 데이터를 긁어와서 간단히 분석해 본 것으로 끝.
거의 제목과 뉴스 첫 줄만으로 최근 트렌드를 반영하는 데이터가 생각보다 잘 뽑혀서 신기했다.
다음 번에는
- 데이터 추가 수집: 뉴스 내용 긁어오기, 2019년 데이터, 댓글 많은 순 데이터
- 주제 별로 키워드 클러스터링 하기
- 예쁜 그래프 라이브러리 찾기
이정도 진행해보아야겠다.