from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from bs4 import BeautifulSoup
import time
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
import matplotlib.pyplot as plt
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
options = webdriver.ChromeOptions()
options.add_argument('--headless')
# 크롤링하는 화면을 보여주지 않겠다는 코드(코랩은 원래 안됨, spider 활용)
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome('chromedriver', options=options)
driver.get('https://youtu.be/qWbHSOplcvY')
driver.implicitly_wait(3)
time.sleep(1.5)
driver.execute_script('window.scrollTo(0,800)')
# 원래 커서 위치에서 800픽셀만큼 내리기
time.sleep(3)
last_height = driver.execute_script("return document.documentElement.scrollHeight")
# 최초 로드시 화면이 가진 스크롤 높이 최대 픽셀값을 추출
while True: # for 문과 달리 무한 루프인데 조건을 충족하면 코드를 벗어남
driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
# 지금 보고 있는 화면이 가진 스크롤 높이 최대 픽셀값만큼 실행
# 즉, 위에서 받은 최대 스크롤 값을 실행하는 것
# ; = window 함수의 특징으로서 code가 끝났으니 다음으로 넘어가라는 표시
time.sleep(1.5)
new_height = driver.execute_script("return document.documentElement.scrollHeight")
# 기존에 받아온 최대 스크롤값을 실행한 후 추가로 생긴 화면이 가진 스크롤 높이 최대 픽셀값 추출
if new_height == last_height: # 추가 스크롤 값 없으면 멈춰
break
last_height = new_height # 스크롤 더 있으면 다시 담아줘(last height 리셋)
time.sleep(1.5)
try:
driver.find_element_by_css_selector('#dismiss-button > a').click()
#유튜브 프리미엄 프로모션 팝업창 닫기
time.sleep(1.5)
except:
pass
html_source = driver.page_source
#print(html_source)
soup = BeautifulSoup(html_source, 'html.parser') #파싱 가능한 형태로 만듦
id_list = soup.select('div#header-author > h3 > #author-text > span')
# 아이디 리스트 변수(html 태그 리스트를 담은 것)
comment_list = soup.select('yt-formatted-string#content-text')
# 댓글 리스트 변수(html 태그 리스트를 담은 것)
id_final = [] # 리스트 형태라고 선언
comment_final = [] # 리스트 형태라고 선언
for i in range(len(comment_list)):
temp_id = id_list[i].text
temp_id = temp_id.replace('\n','').replace('\t','').replace(' ','').strip()
id_final.append(temp_id) # 댓글 작성자 담기
temp_comment = comment_list[i].text
temp_comment = temp_comment.replace('\n','').replace('\t','').strip()
comment_final.append(temp_comment) # 댓글 내용 담기
# 데이터 프레임 만들기 (리스트 -> 딕셔너리 활용 -> 데이터프레임)
youtube_dict = {"아이디": id_final, "댓글 내용": comment_final}
youtube_df = pd.DataFrame(youtube_dict)
youtube_df.info()
youtube_df.to_csv('유튜브댓글크롤링220907.csv', encoding ='UTF-8-sig', index = False)
df = pd.read_csv('/content/유튜브댓글크롤링220907.csv')
df.info()
temp_comment = comment_list[i].text
temp_comment = temp_comment.replace('\n','').replace('\t','').replace('\r','').strip()
comment_final.append(temp_comment) # 댓글 내용 담기
text = " ".join(li for li in youtube_df['댓글 내용'].astype(str))
text
import numpy as np
from PIL import Image #PIL : Python Imaging Library
mask = Image.open('/content/1.jpg')
mask = np.array(mask)
plt.subplots(figsize=(25,15))
wordcloud = WordCloud(background_color='black', width = 1000, height=700, mask = mask,
font_path=fontpath).generate(text)
plt.axis('off')
plt.imshow(wordcloud, interpolation='bilinear')
plt.show()
from selenium.webdriver.common.by import By
driver.find_element(By.CSS_SELECTOR, "#comments-button").click()
# locator(즉, 스크롤할 위치) 지정
reply_body = driver.find_element(By.XPATH, "//div[@id='contents']")
# 참고. selector로도 지정가능 -> reply_body = driver.find_element(By.CSS_SELECTOR, "#contents")
last_height = driver.execute_script("return arguments[0].scrollHeight", reply_body)
while True:
driver.execute_script('arguments[0].scrollTop = arguments[0].
scrollTop + arguments[0].scrollHeight;', reply_body)
time.sleep(1.5)
new_height = driver.execute_script("return arguments[0].scrollHeight" , reply_body)
print('last_height: ', last_height, 'new_height: ', new_height)
if new_height == last_height:
break
last_height = new_height
time.sleep(1.5)
일반 유튜브 동영상과 달리 팝업으로 댓글창이 뜨기 때문에 댓글이 속한 div를 변수(reply_body)로 설정해 그 안에서 최대 스크롤 값을 가져올 수 있도록 한다.
이 때, 댓글이 속한 div의 Xpath나 css selector의 이름으로 수집 가능하다.
교수님께서 작성하신 Xpath와 내가 실제로 Xpath를 복사한 값이 달라서 고민 중이다. 원래 복사되는 값은 @id="contents" 인데, 작은 따옴표로만 코드가 실행된다. 아마 큰 따옴표로 감싸진 상황에서 큰 따옴표로 또 감싸면 안 되는 것 같긴 한데 다시 확인이 필요하다.
window 객체의 scrollTo는 문서를 지정된 좌표로 스크롤해주는 기능을 한다.
.scrollTop()은 선택한 요소의 스크롤바 수직 위치를 반환하거나 스크롤바 수직 위치를 수집한다.
arguments[0]' means first index of page starting at 0.
Where an 'Element' is the locator on the web page. (이 코드에서는 reply_body)
스크롤 참고사이트: https://www.guru99.com/scroll-up-down-selenium-webdriver.html (자바스크립트를 활용한 코드이긴 하지만 참고 가능)