일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 더현대서울 맛집
- 우분투
- 프로그래머스
- leetcode
- 금융문자분석경진대회
- programmers
- Kaggle
- ChatGPT
- 편스토랑 우승상품
- 맥북
- Docker
- 편스토랑
- gs25
- github
- hackerrank
- 캐치카페
- AI 경진대회
- dacon
- 프로그래머스 파이썬
- 데이콘
- PYTHON
- ubuntu
- Real or Not? NLP with Disaster Tweets
- Git
- Baekjoon
- 백준
- SW Expert Academy
- 코로나19
- 파이썬
- 자연어처리
- Today
- Total
솜씨좋은장씨
[Python]Selenium을 사용하여 유튜브 댓글 가져오기 본문
제가 즐겨보는 Youtube B Man채널에서 제 최애 영화인 어벤져스 엔드게임의 영화 명장면을 정리한 어벤져스 엔드게임 명장면 총정리라는 영상의 댓글 가져오기를 해보았습니다.
인스타그램 크롤링 코드가 필요하신 분은 아래의 링크를 참고해주세요!
1. requests와 BeautifulSoup를 활용하여 시도하기
처음에는 requests와 BeautifulSoup를 사용하여 댓글 가져오기를 시도했습니다.
import requests
from bs4 import BeautifulSoup
url = 'https://www.youtube.com/watch?v=xKf0soeFJtY'
req = requests.get(url)
soup = BeautifulSoup(req.text, 'lxml')
youtube_user = soup.select('div#header-author > a > span')
youtube_comments = soup.select('yt-formatted-string#content-text')
위의 코드로 시도했으나 youtube_user와 youtube_comments를 출력해보면
아무것도 받아오지 못한 것을 알 수 있습니다.
구글 크롬의 개발자도구를 활용하여 이유를 확인할 수 있었습니다.
개발자 도구로 동영상 페이지에서 스크롤 전과 후의 html코드를 확인해보면
스크롤 전
스크롤 후
스크롤 전과 후를 보면 스크롤 전에는 별다른 데이터를 가지고 있지않지만 스크롤 후에 동적으로 데이터 값을 가져오는 모습을 보이고 있는 것을 볼 수 있었습니다.
이런 경우 우리가 사용할 수 있는 라이브러리는 Selenium입니다.
설치는 아래의 링크를 참고하기 바랍니다.
2. Selenium활용하여 다시 시도해보기
from selenium import webdriver as wd
from bs4 import BeautifulSoup
import time
driver = wd.Chrome(executable_path="chromedriver.exe")
url = 'https://www.youtube.com/watch?v=xKf0soeFJtY'
driver.get(url)
last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
while True:
driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
time.sleep(3.0)
new_page_height = driver.execute_script("return document.documentElement.scrollHeight")
if new_page_height == last_page_height:
break
last_page_height = new_page_height
html_source = driver.page_source
driver.close()
soup = BeautifulSoup(html_source, 'lxml')
이번엔 Selenium을 활용하여 시도해 보았습니다.
앞 서 스크롤을 해주어야 데이터가 로딩되는 것을 보았기에
아래의 코드를 사용하여 현재 페이지의 가장 아래까지 스크롤하였습니다.
last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
while True:
driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
time.sleep(3.0)
new_page_height = driver.execute_script("return document.documentElement.scrollHeight")
if new_page_height == last_page_height:
break
last_page_height = new_page_height
코드를 실행하면
자동으로 스크롤 하여 최대한 아래로 내려갑니다.
끝까지 내려가도록 코드를 작성하긴 하였지만 네트워크 상태, 개발 환경의 성능에 따라 다를 수 있습니다.
아직 위의 코드에는 단순히 time함수로 3초에 한번씩 스크롤을 내리라고만 하고 있기때문에 3초이내에 새로운 댓글이 로딩되지않는다면 끝까지 내려가지 않고 중간에 멈추고 종료되는 것 같습니다.
html_source = driver.page_source
최대한 아래로 내려갔다면 위의 코드로 페이지의 데이터를 받아옵니다.
soup = BeautifulSoup(html_source, 'lxml')
그럼 받아온 데이터를 BeautifulSoup로 파싱해줍니다.
이 코드에서는 lxml parser를 사용했습니다.
자 그럼 받아온 코드에서 댓글을 단 유저 ID, 댓글을 받아와 보겠습니다.
크롬 개발자도구를 활용하여 태그의 id또는 class값을 확인합니다.
댓글 단 유저이름은 id값이 headear-author인 div태그 안에있는 a태그안에 들어있는 것을 확인할 수 있습니다.
댓글은 id값이 content-text인 yt-formatted-string태그 안에 값이 들어있는 것을 확인할 수 있습니다.
BeautifulSoup의 select함수를 사용하여 코드로 구현하면 아래와 같습니다.
youtube_user_IDs = soup.select('div#header-author > a > span')
youtube_comments = soup.select('yt-formatted-string#content-text')
str_youtube_userIDs = []
str_youtube_comments = []
for i in range(len(youtube_user_IDs)):
str_tmp = str(youtube_user_IDs[i].text)
# print(str_tmp)
str_tmp = str_tmp.replace('\n', '')
str_tmp = str_tmp.replace('\t', '')
str_tmp = str_tmp.replace(' ','')
str_youtube_userIDs.append(str_tmp)
str_tmp = str(youtube_comments[i].text)
str_tmp = str_tmp.replace('\n', '')
str_tmp = str_tmp.replace('\t', '')
str_tmp = str_tmp.replace(' ', '')
str_youtube_comments.append(str_tmp)
받아온 데이터에 들어있는 의미없는 값들을 처리해줍니다.
for i in range(len(str_youtube_userIDs)):
print(str_youtube_userIDs[i], str_youtube_comments[i])
위와 같이 처리된 데이터를 출력하여 제대로 처리가 되었는지 확인해봅니다.
잘 처리는 되었으나 가독성의 면에서 떨어지는 것을 볼 수 있습니다.
3. 가져온 댓글 Pandas의 DataFrame을 활용하여 가독성 높이기
import pandas as pd
pd_data = {"ID":str_youtube_userIDs, "Comment":str_youtube_comments}
youtube_pd = pd.DataFrame(pd_data)
먼저 str_youtube_userIDs와 str_youtube_comments의 데이터를 가지는 pd_data라는 딕셔너리를 만들어주고
pd.DataFrame(pd_data)하여 DataFrame을 만들어줍니다.
만들어진 DataFrame을 확인해보면
조금은 보기 편해진 것을 볼 수 있습니다.
4. 아직 의문으로 남은점
댓글은 2417개로 표시되지만
Selenium을 실행하여 데이터를 가져오면 실행할때마다
40~300개 사이의 계속 다른 개수의 데이터를 받아오는 점이 의문입니다.
추측 1
개발 환경의 컴퓨터 성능이나 네트워크 성능에의해 3초 이내에 로딩이 되지 않아 Webdriver가 종료된다.
추측 2
Webdriver에서 데이터를 받아올 때 까지 기다려주는 함수를 사용하지않아 Webdriver가 다 받아오기 전에 종료된다.
의문점은 더 공부해서 해결 후 포스팅 해보려합니다~
5. 질문에 대한 답변들
Q. 여러 URL 속의 댓글을 크롤링하고 싶어요!
A. 아래와 같이 크롤링하고 싶은 url들을 리스트에 담은 후 반복문을 통해 실행하면됩니다.
from selenium import webdriver as wd
from bs4 import BeautifulSoup
import time
urls = ['https://www.youtube.com/watch?v=xKf0soeFJtY', 'https://www.youtube.com/watch?v=_SgZ0VqJd3w', 'https://www.youtube.com/watch?v=m17R1LMhp3Q&t=452s', 'https://www.youtube.com/watch?v=C_DQTLCERnM', 'https://www.youtube.com/watch?v=7hD2L89cjWc']
html_sources = []
for i in range(0, 5):
driver = wd.Chrome(executable_path="./chromedriver")
driver.get(urls[i])
last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
while True:
driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
time.sleep(3.0)
new_page_height = driver.execute_script("return document.documentElement.scrollHeight")
if new_page_height == last_page_height:
break
last_page_height = new_page_height
html_source = driver.page_source
html_sources.append(html_source)
print("OK")
driver.quit()
여러 질문 들에 대한 답변을 반영하여 코드를 수정하여 아래의 GitHub에 올려두었습니다.
추후 명령어로 사용이 가능하도록 패키지화 시켜볼 예정입니다.
잘 사용하셨다면 Star한번씩 눌러주세요~
읽어주셔서 감사합니다.
'Programming > Python' 카테고리의 다른 글
[Python]과거의 데이터로 최적의 추석 귀경시간 추측해보기(feat, matplotlib) (0) | 2019.09.15 |
---|---|
[Python]지난 2년간의 추석 귀경길 도시 구간별 소요시간 파이썬으로 데이터 받아보기 (0) | 2019.09.14 |
[Python]연안 여객터미널 실시간 운항정보 API 활용기 (2) | 2019.09.13 |
[Python]VirtualBox에 설치된 Ubuntu에서 Jupyter Notebook설치 후 Windows에서 원격접속 설정하기 (2) | 2019.09.12 |
[Python]Ubuntu18.04 LTS에 Anaconda설치하기 (2) | 2019.09.12 |