사람들이 가장 자주 사용하는 사이트인 유튜브에는 많은 양의 데이터가 매일 쌓이고 있습니다.
오늘은 사람들의 반응을 알아볼 수 있는 동영상 댓글 데이터를 수집(크롤링)해보고
이를 가공, 전처리하는 프로젝트를 진행해보겠습니다.
댓글 크롤링하는 영상 : https://www.youtube.com/watch?v=CuklIb9d3fI
최근 가장 핫한 가수인 BTS의 신곡이 나와서 해당 유튜브 영상에 대한 댓글 데이터를 크롤링해보겠습니다.
데이터 구성 : 댓글 내용, 댓글 저자 id, 댓글 날짜, 좋아요 숫자
보시다시피 유튜브는 유저 반응형 웹사이트입니다.
유저의 행동(스크롤 업다운)에 따라 숨어 있던 html 값들이 나오는 구조입니다.
따라서, 셀레니움으로 html 값을 가져올 때 스크롤 다운하는 코드를 넣어줘야 합니다.
# 모듈 import
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from tqdm import tqdm
import time
import re
# 셀레니움 옵션 설정
options = webdriver.ChromeOptions()
# options.add_argument('headless') # 크롬 띄우는 창 없애기
options.add_argument('window-size=1920x1080') # 크롬드라이버 창크기
options.add_argument("disable-gpu") #그래픽 성능 낮춰서 크롤링 성능 쪼금 높이기
options.add_argument("user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36") # 네트워크 설정
options.add_argument("lang=ko_KR") # 사이트 주언어
driver = webdriver.Chrome(ChromeDriverManager().install(),
chrome_options=options)
# 크롤링 목표 : 해당 영상에 대한 댓글 id, 댓글 내용, 댓글의 좋아요 개수, 날짜 추출
data_list = []
driver.get("https://www.youtube.com/watch?v=CuklIb9d3fI")
# 스크롤 내리기
body = driver.find_element_by_tag_name('body')
last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
while True:
driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
time.sleep(2)
new_page_height = driver.execute_script("return document.documentElement.scrollHeight")
if new_page_height == last_page_height:
break
이번에는 javascript를 활용해서 스크롤을 내렸습니다.
해당 영상의 길이가 워낙 길어서 스크롤이 다 내려갈 때까지 반복문으로 설정했는데,
일정 범위만 스크롤을 내릴 때는 아래의 코드를 사용하면 편합니다.
# 숫자 값은 마음대로 설정 가능
driver.execute_script("window.scrollTo(0,1000)")
데이터가 html에 다 표시되었으면, 페이지 소스를 가져와 html 파싱하는 작업을 거쳐줘야 합니다.
# bs4 html 파싱
html0 = driver.page_source
html = BeautifulSoup(html0, 'html.parser')
comments_list = html.findAll('ytd-comment-thread-renderer', {'class': 'style-scope ytd-item-section-renderer'})
PageSource를 한 번 살펴보면, ytd-comment-thread-renderer의 class : style-scope ytd-item-section-renderer로 댓글이 들어가 있음을 알 수 있습니다.
box를 찾으면, 그 안에 있는 세부내용을 찾기는 수월합니다.
마우스 우클릭으로 페이지 소스 보기를 통해 원하는 데이터가 들어간 class나 id를 찾으면 됩니다.
for j in range(len(comments_list)):
## 댓글 내용
comment = comments_list[j].find('yt-formatted-string', {'id': 'content-text'}).text
comment = comment.replace('\n', '') # 줄 바뀜 없애기
comment = comment.replace('\t', '') # 탭 줄이기
# print(comment)
## 유튜브 id
youtube_id = comments_list[j].find('a', {'id': 'author-text'}).span.text
youtube_id = youtube_id.replace('\n', '') # 줄 바뀜 없애기
youtube_id = youtube_id.replace('\t', '') # 탭 줄이기
youtube_id = youtube_id.strip()
## 댓글 날짜
raw_date = comments_list[j].find('yt-formatted-string', {
'class': 'published-time-text above-comment style-scope ytd-comment-renderer'})
date = raw_date.a.text
## 댓글 좋아요 개수 (0인 경우 예외 처리)
try:
like_num = comments_list[j].find('span',
{'id': 'vote-count-middle',
'class': 'style-scope ytd-comment-action-buttons-renderer',
'aria-label': re.compile('좋아요')}).text
like_num = like_num.replace('\n', '') # 줄 바뀜 없애기
like_num = like_num.replace('\t', '') # 탭 줄이기
like_num = like_num.strip()
except:
like_num = 0
data = {'comment': comment, 'youtube_id': youtube_id, 'date': date, 'like_num': like_num}
data_list.append(data)
# print(data)
이런 식으로 박스 리스트에 대한 for문을 만들어주고 각 데이터가 들어간 id와 class를 find 함수로 찾아서 가공해주면 됩니다. 개인적으로 데이터를 수집하는 과정에서부터 깔끔하게 전처리하는 방식을 선호하기에 가공하는 부분까지 함께 만들었습니다.
이제 완성된 데이터 리스트를 데이터 프레임화하여 엑셀로 만들어주면 완성된 데이터 테이블을 확인할 수 있습니다.
result_df = pd.DataFrame(data_list,
columns=['comment','youtube_id','date','like_num'])
result_df.to_excel(f'C:/Users/코딩하는 금융인/Desktop/comment_youtube.xlsx', index=False)
driver.close()
▣ 데이터 확인
comment | youtube_id | date | like_num |
Da na na na na na~ | Rabbit Adventures | 1주 전 | 5.6만 |
“Yolunuzu kaybetmek, o yolu bulmanın yoludur.”- BTS, “Kayıp”-BTS, "Lost"TURKISH ARMY AZE ARMY | ÖLÜM VAR!! | 1시간 전 | 34 |
Popular opinion: Everyone agrees that jungkook can do everything | Khadijah mohd Amim | 1시간 전 | 52 |
Nə qədər uzağa gedəcəyimi bilmirəm amma harası olursa olsun armylərlə getmək istəyirəm~JiminAzerb@!jan armyTürk!sh army | aze army 🇦🇿 | 3시간 전 | 46 |
“Başkalarını sevmek istiyorsan, önce kendini sevmelisin.” - RMTURKISH ARMY AZE ARMY | ÖLÜM VAR!! | 2시간 전 | 33 |
˙˙˙˙ | ˙˙˙˙ | ˙˙˙˙ | ˙˙˙˙ |
역시 세계적인 그룹으로 거의 모든 댓글이 외국인들로 이루어져 있음을 알 수 있으며,
약 2천개 가량의 데이터를 한 번 수집 테스트를 한 결과, 결측값은 나오지 않고 댓글별로 잘 뽑혔습니다.
댓글 데이터는 단어별로 추출하여 워드 클라우드나 선호도 파악 등 여러 가지 데이터 분석에 쓰일 수 있으며,
나중에 이와 같은 데이터 분석 프로젝트에 대해서도 포스팅 하도록 하겠습니다. 긴 글 봐주셔서 감사합니다.
'Programming > Python' 카테고리의 다른 글
[Python] 순열, 조합 itertools 설명 및 예제 (0) | 2021.08.24 |
---|---|
파이썬 문제 및 연습 사이트 추천 (5) | 2021.08.03 |
파이썬 한글 자음 모음 조합하기 (NLP) (4) | 2021.07.17 |
파이썬 영어 한글 발음으로 변환하기 (콩글리시) (4) | 2021.07.05 |
파이썬 유튜브 크롤링 셀레니움 2편 (2) | 2021.06.22 |
댓글