본문 바로가기

About 배우고 익히는법/Python

유튜브 댓글 크롤링하기

동적 크롤링을 이용하여 댓글 가져오기

데이터프레임 형식으로 저장할 때 인덱스 값으로 숫자가 붙는 것을 해결하기 위해

아래 코드 사용

컬럼이름을 지정하지 않으면 for문으로 돌릴 때 인덱스 번호만 출력됨..(0,1,2,3,...으로)

url=[] filename = 'urlData.csv' urllist = pd.read_csv(filename, encoding='utf-8') #print(urllist) print(urllist['0']) for i in urllist['0']: print(i) url.append(i) print(len(url))

댓글 가져오는 코드를 먼저 짠 다음

함수로 처리하여

url반복적으로 가져오는 코드로 작성

from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.common.keys import Keys from datetime import datetime import pandas as pd import time import re driver = webdriver.Chrome('C:/chromedriver_win32/chromedriver.exe') print('크롤링 시작') url=[] filename = 'urlData.csv' urllist = pd.read_csv(filename, encoding='utf-8') #print(urllist) #print(urllist['0']) def getCmt(url): youtube_url = url #유튜브 주소 driver.get(youtube_url) body = driver.find_element_by_tag_name("body") print('시작') #(스크롤 내리기) num_of_pagedowns = 7 datetime.today() while num_of_pagedowns: body.send_keys(Keys.PAGE_DOWN) time.sleep(2) num_of_pagedowns -= 1 try: driver.find_element_by_xpath('//*[@id="sort-menu"]').click() #driver.find_element_by_xpath('//*[@id="menu"]/a[@tabindex="-1"]').click() driver.find_element_by_xpath('//*[@id="menu"]/a[2]/paper-item/paper-item-body/div[text()="최근 날짜순"]').click() except Exception as e: pass #10번만 반복 (스크롤 횟수 설정 필요) num_of_pagedowns = 20 while num_of_pagedowns: body.send_keys(Keys.PAGE_DOWN) time.sleep(2) num_of_pagedowns -= 1 html = driver.page_source result = BeautifulSoup(html,'html.parser') #print(html) body = result.find("body") #print(body) title = body.find_all('yt-formatted-string', attrs={'class':'style-scope ytd-video-primary-info-renderer'}) title1=title[0].get_text() print(title1) thread=body.find_all('ytd-comment-renderer', attrs={'class':'style-scope ytd-comment-thread-renderer'}) cmtlist=[] for items in thread: #댓글 내용 div = items.find_all('yt-formatted-string', attrs={'id':'content-text'}) #기간(시점) div2 = items.select('yt-formatted-string > a')[0].get_text() for lists in div: #print(lists) if lists != None: try: cmt = lists.string textcmt = re.sub(r'[^\w]',' ',cmt) cmtlist.append([textcmt, div2]) print(textcmt) except TypeError as e: pass else: pass #cmtlist.append([textcmt, div2]) print(div2) print('-'*50) print(len(cmtlist)) result = pd.DataFrame(cmtlist) result.to_csv(title1+'.csv', encoding='utf-8') for i in (urllist['0'])[7:]: print(i) url.append(i) getCmt(i) print(len(url)) print('finished')

오류 코드 발생

Traceback (most recent call last):

File "D:\bigdata0709\jspstudy\jspws\MyPython\newpj\youtub\comment_c(revised).py", line 101, in <module>

getCmt(i)

File "D:\bigdata0709\jspstudy\jspws\MyPython\newpj\youtub\comment_c(revised).py", line 96, in getCmt

result.to_csv(title1+'.csv', encoding='utf-8')

File "C:\Anaconda3\lib\site-packages\pandas\core\frame.py", line 1745, in to_csv

formatter.save()

File "C:\Anaconda3\lib\site-packages\pandas\io\formats\csvs.py", line 156, in save

compression=self.compression)

File "C:\Anaconda3\lib\site-packages\pandas\io\common.py", line 400, in _get_handle

f = open(path_or_buf, mode, encoding=encoding)

OSError: [Errno 22] Invalid argument: '제목?.csv'

->저장 시 파일 이름에 특수문자 들어가면 발생하는 오류

특수문자 제외처리 필요함

title = re.sub(r'[^\w]',' ',title)로 특수문자 제거한 뒤 저장


댓글이 더이상 안나올 때까지 스크롤을 내린 다음 댓글을 가져오려고 코드를 일부 수정

전체 댓글 수와 댓글을 저장한 list의 길이가 같으면 스크롤 내리기를 멈추게 하려고 했는데

댓글에 달린 대댓글...까지 전체 댓글수에 포함되어있어서

그것까지 계산했는데 오류가나고, 만 개 정도 되는 댓글은 스크롤 내리는것도 시간 너무 오래걸려서

일단은 3500개까지 저장하면 중간에 멈추는 것으로 수정함

그러나 댓글이 하나도 없을 경우.. 무한으로 스크롤이 내려가게 되어버려서 추후 수정필요

import pandas as pd import time import re import os driver = webdriver.Chrome('C:/chromedriver_win32/chromedriver.exe') print('크롤링 시작') url=[] filename = 'urlData.csv' urllist = pd.read_csv(filename, encoding='utf-8') #print(urllist) #print(urllist['0']) def getCmt(url): youtube_url = url #유튜브 주소 driver.get(youtube_url) body = driver.find_element_by_tag_name("body") print('시작') #(스크롤 내리기) num_of_pagedowns = 7 datetime.today() while num_of_pagedowns: body.send_keys(Keys.PAGE_DOWN) time.sleep(2) num_of_pagedowns -= 1 try: driver.find_element_by_xpath('//*[@id="sort-menu"]').click() #driver.find_element_by_xpath('//*[@id="menu"]/a[@tabindex="-1"]').click() driver.find_element_by_xpath('//*[@id="menu"]/a[2]/paper-item/paper-item-body/div[text()="최근 날짜순"]').click() except Exception as e: pass #10번만 반복 (스크롤 횟수 설정 필요) num_of_pagedowns = 30 while True: body.send_keys(Keys.PAGE_DOWN) time.sleep(2) num_of_pagedowns -= 1 # body = result.find("body") # last = body.find_all('div', attrs={'id':'continuations'}) # if last not in body: # break html = driver.page_source result = BeautifulSoup(html,'html.parser') #print(html) body2 = result.find("body") #print(body) title = body2.find_all('yt-formatted-string', attrs={'class':'style-scope ytd-video-primary-info-renderer'}) title1=title[0].get_text() title1 = re.sub(r'[/\:*?<>"|!]',' ',title1) #print(title1) thread=body2.find_all('ytd-comment-renderer', attrs={'class':'style-scope ytd-comment-thread-renderer'}) last = body2.find('yt-formatted-string', attrs={'class':'count-text style-scope ytd-comments-header-renderer'}) last = last.string print(last) last_t = re.sub('[^\d]','',last) last_t = int(last_t) plus_c = 0 plus_cmt = body2.find_all('span',attrs={'id':'more-text'}) for count in plus_cmt: count = count.get_text().strip() #print(count) if count == '답글 보기': plus_c += 1 else: cmts = re.sub('[^\d]','',count) plus_c += int(cmts) #print(plus_c) #print(last_t) cmtlist=[] for items in thread: #댓글 내용 div = items.find_all('yt-formatted-string', attrs={'id':'content-text'}) #기간(시점) div2 = items.select('yt-formatted-string > a')[0].get_text() for lists in div: #print(lists) if lists != None: try: cmt = lists.string #textcmt = re.sub(r"[^\w^?!',.%$]",' ',cmt) cmtlist.append([cmt]) #print(textcmt) except TypeError as e: pass else: pass #cmtlist.append([textcmt, div2]) num_c = (len(cmtlist) +plus_c ) print(num_c) if num_c >= (last_t-10) or num_c>=3500: break print(len(cmtlist)) print('-'*50) result = pd.DataFrame(cmtlist) #csv파일 저장 폴더 생성, 파일 저장 dir_path = 'c:' dir_name = 'imsi2' if not os.path.isdir(dir_path+'/'+ dir_name + '/'): os.mkdir(dir_path+'/'+ dir_name + '/') try : result.to_csv(dir_path+'/'+dir_name+'/'+title1+'.csv', encoding='utf-8') except Exception as e: print(e, "저장 오류 발생") for i in (urllist['0'])[58:]: print(i) url.append(i) getCmt(i) print(len(url)) print('finished')