전체 피드백
Important Feedback
- 나중엔 주피터 노트북이 아닌 파이썬 파일로 만들어 사용하게 되기 때문에
- 로그란?
- 코드의 진행과정을 출력으로 확인해볼 수 있게 하는 것
- 처음은
logger라이브러리를 활용해보는 것을 추천합니다.
- 로딩 바를 나타내주는
tqdm도 있습니다.- 과제 내용 이외에 완성된 데이터셋을 가지고 어떤 것을 할 수 있을지, 미리 전처리한다면 어떻게 해볼 수 있을 지 생각해 보는 것을 추천합니다.
- 보통 자신이 손님일 때 이 결과물을 받으면 어디가 신경 쓰일까를 먼저 생각해봅니다.
- 이에 대한 예시
- Ex1) 좋아요는 숫자이니까 datatype을 int로 바꾸고 빈칸은 0으로 대체
- Ex2) id 앞에 공통적으로
@가 존재하니까 제외하여 활용성을 높임- Ex3) 최종 데이터프레임의 열 이름을 영어/한글 통일시키기, 컬럼 위치 재조정하기
크롬 창 생성 및 유튜브 주소로 접속하기
1. 중간 피드백
- 코드가 어떤 행동을 취하는 것인지 바로 파악이 힘든 경우에는 가독성을 위해 함수화 해주는 것도 좋습니다.
def pause(driver):
ActionChains(driver).send_keys('k').perform()- 자바 스크립트로 접근하는 방법입니다.
def pause(driver):
video = driver.find_element(By.TAG_NAME, "video")
ispause = driver.execute_script("return arguments[0].paused;", video)
if not ispause:
driver.execute_script("arguments[0].pause();", video)과제3. 전체 함수 만들기
2. 중간 피드백
- 크롤링하는 함수로 개발하는 과정을 담았습니다.
- “이러한 방법으로도 할 수 있구나”라고 이해하고, 적용하고 싶은 부분만 따로 정리하시면 될 것 같습니다.
연구원님의 크롤링하는 함수 개발하는 과정
STEP 1. 순차적 개발
# Setting
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import pandas as pd
from urllib.parse import parse_qs
url = "https://www.youtube.com/watch?v=0BWScn_OWPk"- 유튜브 영상 주소로 들어가면 영상이 자동으로 실행되는 경우와 안되는 경우가 있다.
- 이를 변수로 지정해 boolean으로 실행한다면 멈추고 멈춰있으면 그대로 두는 코드를 짠다.
# 크롬 창 열기
options = Options()
driver = webdriver.Chrome(options = options)
# 창모드 전체화면으로 크기 늘리기
driver.maximize_window()
# 로딩시간: 페이지 로딩
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.ID, "below")))
# 유튜브 주소 접속하기
driver.get(url)
# 로딩시간: div마다 로딩되는 시간이 다르다는 것을 확인, 제일 마지막에 나오는 below요소를 기준으로 함.
# 로딩될 때 영상이 먼저 나오고 마지막으로 댓글이 나온다.
# 그래서 댓글창까지 다 나오면 로딩완료라는 뜻을 하렬고 ID, below까지 하신거다
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.ID, "below")))
# 비디오 멈추기: 자동실행 될 때가 있고, 안될 때가 있다.
video = driver.find_element(By.TAG_NAME, "video")
# `return arguments[0].paused;`는 영상이 멈춰있는지 아닌지 True, False로 반환해준다.
# JavaScript 언어다.
ispause = driver.execute_script("return arguments[0].paused;", video)
print(ispause)
if not ispause:
# `pause()`는 영상을 멈추게 하는 JavaScript 함수이다.
driver.execute_script("arguments[0].pause();", video)# 스크롤 다운
# 댓글창이 보여야 활성화 되기 때문에 살짝 내리는 과정 필요
driver.execute_script("window.scrollTo(0, 280);")
time.sleep(1)
last_height = driver.execute_script("return document.documentElement.scrollHeight")
for i in range(5):
# 내린다
driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
time.sleep(2)
# 비교
new_height = driver.execute_script("return document.documentElement.scrollHeight")
if new_height == last_height:
break
last_height = new_height- 로그를 보여줌으로서 코드의 실행 과정이 어느정도 진행되었는지 알 수 있다.
- 이러한 로그 프린트는 알아두는게 좋을 거 같다.
- 또한 중간 중간마다
print()를 통해 값이 제대로 저장되었는지 확인과 출력했을 때 이 숫자 또는 출력값이 무엇을 뜻하는지 알아보기 쉽게 되어 있어서 좋다.
# 추출하기
# 데이터를 담을 빈 딕셔너리 만들기
comment_data_dict = {"UserID": [], "Comment":[],"Likes":[]}
# 댓글 불러오기
number_comments = driver.find_elements(By.CLASS_NAME, 'style-scope ytd-comment-view-model')
# `print()`를 통해 불러올 댓글 수를 알아보기 쉬워 결과값을 볼 때 한눈에 보인다.
print(f"불러올 댓글 수: {len(number_comments)}")
# loop를 통해 데이터 받기 및 저장하기
cnt = 0
print("START", end=" ")
for i in range(len(number_comments)):
# 텍스트 추출
user_id = driver.find_elements(By.CSS_SELECTOR, '#author-text')[i].text
comment_text = driver.find_elements(By.CSS_SELECTOR, "#content-text")[i].text
num_likes = driver.find_elements(By.XPATH, '//*[@id="vote-count-middle"]')[i].text
# comment_data_dict 딕셔너리에 데이터 넣기
comment_data_dict["UserID"].append(user_id[1:])
comment_data_dict["Comment"].append(comment_text)
comment_data_dict["Likes"].append(num_likes)
# 로그 프린트
cnt += 1
if cnt > 0 and cnt % 20 == 0:
print(cnt, end=" > ")
print("End")
print(comment_data_dict)parse_qs()는 지정된 쿼리스트링을 해석하여 dict()로 반환합니다.- unquote 정리노트
print(url.split('?')[-1])
# 출력값
v=0BWScn_OWPk# videoid 추출: url에서 v의 value 추출하기
query = parse_qs(url.split('?')[-1])
print(query)
videoid = query["v"][0]# 데이터 프레임 만들기
df_comments = pd.DataFrame(comment_data_dict)
# videoID column 추가
df_comments["video_ID"] = videoid
# .csv파일로 저장
df_comments.to_csv("./youtube_comments_crawling.csv")- 로그
- for문의
range에 맞춰cnt % 20 == 0을 통해 20, 40, 60, 80, … 으로 출력되게 하였다.
cnt = 0
print("START", end=" ")
for i in range(len(number_comments)):
pass
cnt += 1
if cnt > 0 and cnt % 20 == 0:
print(cnt, end=" > ")# 출력값
START 20 > 40 > 60 > 80 > 100 > 120 > End
STEP 2. 계획 설정
- 전체 함수 이름:
get_youtube_comment(url, n_scroll, save_path='./') - 덩어리별로 분류
- 크롬 창 열고, 동영상 재생중이라면 일시정지 →
open_chrome(url)output : driver - 댓글 스크롤 다운 →
scroll_down(driver, n_scroll)output : driver - 정보 추출 →
crawling_comment(driver)output : dataframe - 데이터 프레임 저장
- 크롬 창 열고, 동영상 재생중이라면 일시정지 →
STEP 3. 최종 코드 정리
- 전체적으로 쓰이는 함수
- 다른 곳에서도 자주 쓰이는 함수들을 만들어 놓으면 편할거 같다.
- 연구원님이 말씀하신 함수를 만들어두라는게 무엇인지 알거 같다.
# Fuction 정리
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import pandas as pd
from urllib.parse import parse_qs
# Functions: 자주 사용되는 함수
def loading(driver, element=(By.TAG_NAME, "body")):
"""페이지가 로딩될 때까지 기다리는 함수"""
# 로딩시간
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located(element))
def video_pause(driver):
video = driver.find_element(By.TAG_NAME, "video")
ispause = driver.execute_script("return arguments[0].paused;", video)
if not ispause:
driver.execute_script("arguments[0].pause();", video)
def scroll_down(driver, n_scroll):
"""페이지를 스크롤다운 하는 함수"""
# 댓글창이 보여야 활성화 되기 때문에 살짝 내리는 과정 필요
driver.execute_script("window.scrollTo(0, 280);")
time.sleep(2)
last_height = driver.execute_script("return document.documentElement.scrollHeight")
for i in range(5):
# 내린다
driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
time.sleep(2)
# 비교
new_height = driver.execute_script("return document.documentElement.scrollHeight")
if new_height == last_height:
break
last_height = new_height
def get_videoid(url:str):
"""URL에서 videoid 추출하는 함수"""
query = parse_qs(url.split('?')[-1])
videoid = query["v"][0]
return videoid- 이번 과제에서 사용할 함수
# Functions: 이번 과제에서 사용할 함수
def open_chrome(url):
"""크롬 창을 생성하여 url로 이동하는 함수"""
# 크롬 창 열기
options = Options()
driver = webdriver.Chrome(options = options)
# 창모드 전체화면으로 크기 늘리기
driver.maximize_window()
# 로딩시간
loading(driver)
# 유튜브 주소 접속하기
driver.get(url)
# 유튜브 로딩시간
loading(driver, element=(By.ID, "below"))
# 동영상 재생되면 멈춤
video_pause(driver)
return driver
def crwaling_comment(driver):
"""댓글 데이터프레임을 만드는 함수"""
# 데이터를 담을 빈 딕셔너리 만들기
comment_data_dict = {"UserID": [], "Comment":[],"Likes":[]}
# 댓글 불러오기
number_comments = driver.find_elements(By.CLASS_NAME, 'style-scope ytd-comment-view-model')
print(f"-불러올 댓글 수: {len(number_comments)}")
# loop를 통해 데이터 받기 및 저장하기
cnt = 0
print("-START", end=" ")
for i in range(len(number_comments)):
# 텍스트 추출
user_id = driver.find_elements(By.CSS_SELECTOR, '#author-text')[i].text
comment_text = driver.find_elements(By.CSS_SELECTOR, "#content-text")[i].text
num_likes = driver.find_elements(By.XPATH, '//*[@id="vote-count-middle"]')[i].text
# comment_data_dict 딕셔너리에 데이터 넣기
comment_data_dict["UserID"].append(user_id[1:])
comment_data_dict["Comment"].append(comment_text)
comment_data_dict["Likes"].append(num_likes)
# 로그 프린트
cnt += 1
if cnt > 0 and cnt % 20 == 0:
print(cnt, end=" > ")
print("End")
return comment_data_dict- 메인 함수
# 메인 함수
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import pandas as pd
from urllib.parse import parse_qs
def get_youtube_comment(url, n_scroll=5, save_path="./"):
# video id 추출
video_id = get_videoid(url)
print(f"YOUTUBE ID: {video_id}")
# 크롬 창 열기
print(f"1. 크롬 창을 열고 있습니다.", end=" ")
driver = open_chrome(url)
print(f">>>> 완료")
# 스크롤 다운
scroll_down(driver, n_scroll)
# 딕셔너리 만들기
print(f"2. 댓글을 가져오는 중입니다.")
comment_data_dict = crwaling_comment(driver)
# 데이터 프레임으로 만들기
print(f"3. 데이터프레임으로 변환 중입니다", end=" ")
df_comments = pd.DataFrame(comment_data_dict)
df_comments["videoID"] = video_id
print(">>>> 완료")
# .csv파일로 저장
df_comments.to_csv(save_path + "youtube_comments_crawling.csv")
return df_comments- 실행 코드
# 실행 코드
url = "https://www.youtube.com/watch?v=0BWScn_OWPk"
youtube_comments = get_youtube_comment(url)
# 실행 결과
YOUTUBE ID: 0BWScn_OWPk
1. 크롬 창을 열고 있습니다. >>>> 완료
2. 댓글을 가져오는 중입니다.
-불러올 댓글 수: 120
-START 20 > 40 > 60 > 80 > 100 > 120 > End
3. 데이터프레임으로 변환 중입니다 >>>> 완료(번외) python 함수로 만들기
# 파일 구조
selenium_tool/
│ ├── __init__.py : 모듈을 불러오면 자동으로 실행됨
│ ├── utils.py : 자주 쓰이거나 활용이 많은 함수들의 모임
│ └── youtube_crawling.py : 유튜브 크롤링에만 쓰이는 함수들의 모임
main.py
__init__.pyselenium_tool이라는 모듈을 만들어 뿌리를 만든다.
from selenium_tool.utils import *
from selenium_tool.youtube_crawling import *utils.py
# utils.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
from urllib.parse import parse_qs
def loading(driver, element=(By.TAG_NAME, "body")):
"""페이지가 로딩될 때까지 기다리는 함수"""
# 로딩시간
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located(element))
def video_pause(driver):
video = driver.find_element(By.TAG_NAME, "video")
ispause = driver.execute_script("return arguments[0].paused;", video)
if not ispause:
driver.execute_script("arguments[0].pause();", video)
def scroll_down(driver, n_scroll):
"""페이지를 스크롤다운 하는 함수"""
# 댓글창이 보여야 활성화 되기 때문에 살짝 내리는 과정 필요
driver.execute_script("window.scrollTo(0, 280);")
time.sleep(2)
last_height = driver.execute_script("return document.documentElement.scrollHeight")
for i in range(5):
# 내린다
driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
time.sleep(2)
# 비교
new_height = driver.execute_script("return document.documentElement.scrollHeight")
if new_height == last_height:
break
last_height = new_height
def get_videoid(url:str):
"""URL에서 videoid 추출하는 함수"""
query = parse_qs(url.split('?')[-1])
videoid = query["v"][0]
return videoidyoutube_crawling.py
# youtube_crawling.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium_tool.utils import *
def open_chrome(url):
"""크롬 창을 생성하여 url로 이동하는 함수"""
# 크롬 창 열기
options = Options()
driver = webdriver.Chrome(options = options)
# 창모드 전체화면으로 크기 늘리기
driver.maximize_window()
# 로딩시간
loading(driver)
# 유튜브 주소 접속하기
driver.get(url)
# 유튜브 로딩시간
loading(driver, element=(By.ID, "below"))
# 동영상 재생되면 멈춤
video_pause(driver)
return driver
def crwaling_comment(driver):
"""댓글 데이터프레임을 만드는 함수"""
# 데이터를 담을 빈 딕셔너리 만들기
comment_data_dict = {"UserID": [], "Comment":[],"Likes":[]}
# 댓글 불러오기
number_comments = driver.find_elements(By.CLASS_NAME, 'style-scope ytd-comment-view-model')
print(f"-불러올 댓글 수: {len(number_comments)}")
# loop를 통해 데이터 받기 및 저장하기
cnt = 0
print("-START", end=" ")
for i in range(len(number_comments)):
# 텍스트 추출
user_id = driver.find_elements(By.CSS_SELECTOR, '#author-text')[i].text
comment_text = driver.find_elements(By.CSS_SELECTOR, "#content-text")[i].text
num_likes = driver.find_elements(By.XPATH, '//*[@id="vote-count-middle"]')[i].text
# comment_data_dict 딕셔너리에 데이터 넣기
comment_data_dict["UserID"].append(user_id[1:])
comment_data_dict["Comment"].append(comment_text)
comment_data_dict["Likes"].append(num_likes)
# 로그 프린트
cnt += 1
if cnt > 0 and cnt % 20 == 0:
print(cnt, end=" > ")
print("End")
return comment_data_dictmain.py- [[과제 공부용#if-name—main-|
if __name__ == "__main__"에 대한 노트]]
# main.py
import pandas as pd
from selenium_tool import *
def get_youtube_comment(url, n_scroll=5, save_path="./"):
# video id 추출
video_id = get_videoid(url)
print(f"YOUTUBE ID: {video_id}")
# 크롬 창 열기
print(f"1. 크롬 창을 열고 있습니다.", end=" ")
driver = open_chrome(url)
print(f">>>> 완료")
# 스크롤 다운
scroll_down(driver, n_scroll)
# 딕셔너리 만들기
print(f"2. 댓글을 가져오는 중입니다.")
comment_data_dict = crwaling_comment(driver)
# 데이터 프레임으로 만들기
print(f"3. 데이터프레임으로 변환 중입니다", end=" ")
df_comments = pd.DataFrame(comment_data_dict)
df_comments["videoID"] = video_id
print(">>>> 완료")
# .csv파일로 저장
df_comments.to_csv(save_path + "youtube_comments_crawling.csv")
return df_comments
# 터미널에서 파이썬을 직접 실행하면 아래의 코드가 실행됨
# python main.py
if __name__ == "__main__":
url = "https://www.youtube.com/watch?v=0BWScn_OWPk"
youtube_comments = get_youtube_comment(url)