본문 바로가기

나 취준생/파이썬

웹 스크롤링 연습 ( 유튜브 댓글 )

320x100



내가 최근에 빠진 권진아 노래의 댓글을 크롤링해보자.




# 코드 설계


일단 나는 댓글 수를 먼저 알아야겠다고 생각했다.


왜냐면 유튜브 댓글의 구조가 밑으로 스크롤을 내릴 수록 댓글이 계속 나오는데,


모든 댓글을 스크롤링하려면 스크롤을 계속 반복해야하는데, 언제까지 반복할지는 알 수 없기 때문이다.


그래서 유튜브 댓글 창 맨 위에는 댓글 수가 적혀있어서, 그 html 코드를 따와서 댓글 수만 변수에 저장하고,


스크롤링할 때마다 몇 개씩 댓글이 추가되는지를 구해서, 그 수가 변수보다 커지면 멈추게 해야겠다고 생각했다.


댓글 수를 구하려면 일단 유튜브 창을 띄우고, 창을 최대화시킨 뒤, 스크롤을 한 번 내려야했다.


스크롤을 하지 않고 바로 html 코드를 찾으면 아예 나타나질 않기 때문.


따라서 browser.maximize_window()와 browser.find_element_by_tag_name('html').send_keys(Keys.PAGE_DOWN)를 사용했는데,


time.sleep()을 넣어주지 않으면 창이 제대로 열리기도 전에 내려버려서 효과가 없었다.


그렇게 댓글 수를 뽑아내고, 댓글 수와 같이 나온 처음 댓글들을 리스트에 담고 개수를 세었더니 20개가 나왔다.


( 처음엔 40개가 나왔는데, 리스트 내용을 보니까 '\n' 즉, 아무런 내용 없는 것도 같이 들어있어서 개수가 2배가 되어 나왔다.


그래서 리스트 내용 중에 '\n'만 담겨있으면 리스트에 담기지 않도록 설정했더니 20개로 정상적으로 나왔다. )


그 뒤 browser.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")로 스크롤을 한 번 쭉 내려서


댓글을 한 번 업데이트 해주고, 다시 한 번 창의 댓글들을 리스트에 담고 개수를 세었더니 40개가 나왔다.


즉 업데이트할 때마다 추가되는 개수는 20이라고 결론을 내렸다.


print(num[0].get_text()) -> '댓글 665개'


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
32
33
34
35
36
37
from  bs4  import  BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import urllib.request
import time
binary = 'C:\chromedriver\chromedriver.exe'
browser = webdriver.Chrome(binary)
browser.get("https://www.youtube.com/watch?v=CLR9dytvnmM&list=RDCLR9dytvnmM&start_radio=1")
browser.maximize_window()
time.sleep(2)
browser.find_element_by_tag_name('html').send_keys(Keys.PAGE_DOWN)
time.sleep(2)
html = browser.page_source
soup = BeautifulSoup(html, "lxml")
num=soup.find_all('yt-formatted-string', class_ ='count-text style-scope ytd-comments-header-renderer')
print(num[0].get_text())
comment=soup.find_all('yt-formatted-string',class_ ='style-scope ytd-comment-renderer')
#print(comment)
comment_list=[]
for i in comment:
    if i.get_text()!='''\n''':
        comment_list.append(i.get_text())
print(comment_list)
print(len(comment_list)) #20
print('--------------------------------------------')   
time.sleep(2)
browser.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
time.sleep(2)
html=browser.page_source
soup = BeautifulSoup(html, "lxml")
comment=soup.find_all('yt-formatted-string',class_ ='style-scope ytd-comment-renderer')
comment_list=[]
for i in comment:
    if i.get_text()!='''\n''':
        comment_list.append(i.get_text())
print(comment_list)
print(len(comment_list)) #40






# 코드 설계


이제 스크롤링할 때마다 20개씩 추가된다는 것을 알았으니,

따라서 처음 구한 총 댓글 수에서 매번 20씩을 내리고 그게 0보다 작아질 때까지 계속 2초 간격으로 밑으로 스크롤하도록 설정하는

while문 코드를 짜서, 끝까지 내린 뒤 한 번에 댓글을 스크롤했다.



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
32
33
34
35
36
from  bs4  import  BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import urllib.request
import time
binary = 'C:\chromedriver\chromedriver.exe'
browser = webdriver.Chrome(binary)
browser.get("https://www.youtube.com/watch?v=CLR9dytvnmM&list=RDCLR9dytvnmM&start_radio=1")
browser.maximize_window()
time.sleep(2)
browser.find_element_by_tag_name('html').send_keys(Keys.PAGE_DOWN)
time.sleep(2)
html = browser.page_source
soup = BeautifulSoup(html, "lxml")
num=soup.find_all('yt-formatted-string', class_ ='count-text style-scope ytd-comments-header-renderer')
print(num[0].get_text()) # 댓글 665개
comment_num=int(num[0].get_text()[3:-1]) # 665
#print(comment_num)
comment_list=[]
def scroll(n):
    while (n>0):
        print(n)
        time.sleep(2)
        browser.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
        n-=20
    return 0
scroll(comment_num)
time.sleep(2)
html=browser.page_source
soup = BeautifulSoup(html, "lxml")
comment=soup.find_all('yt-formatted-string',class_ ='style-scope ytd-comment-renderer')
for i in comment:
    if i.get_text()!='''\n''':
        comment_list.append(i.get_text())
print(comment_list)
print(len(comment_list)) # 461




근데 확인해보니 분명 창은 댓글 맨 밑까지 내려와있고 마지막 댓글도 분명 리스트에 있는데, 리스트에는 665가 아닌 461개가 담겨있었다.

약 200개는 무엇인가..했더니?




Aㅏ..이런 답글까지 합쳐져서 665개였고, 난 답글을 제외한 댓글들만 담았던 것.


그래서 내가 하려는 방법으로 하려면, 답글 수까지 전부 구해서 665에서 다시 빼야 최적화된 while문을 만들 수 있다.


아무리 생각해도 이거까지 하면 너무 비효율적이다. (할 수 있을지도 모르겠고)


어떻게 해야 스크롤을 효율적으로 내릴 수 있을까


구글링해봤다.


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
32
33
34
35
36
from  bs4  import  BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import urllib.request
import time
binary = 'C:\chromedriver\chromedriver.exe'
browser = webdriver.Chrome(binary)
browser.get("https://www.youtube.com/watch?v=CLR9dytvnmM&list=RDCLR9dytvnmM&start_radio=1")
browser.maximize_window()
time.sleep(2)
browser.find_element_by_tag_name('html').send_keys(Keys.PAGE_DOWN)
time.sleep(2)
html = browser.page_source
soup = BeautifulSoup(html, "lxml")
num=soup.find_all('yt-formatted-string', class_ ='count-text style-scope ytd-comments-header-renderer')
print(num[0].get_text()) # 댓글 665개
comment_num=int(num[0].get_text()[3:-1]) # 665
#print(comment_num)
comment_list=[]
last_page_height = browser.execute_script("return document.documentElement.scrollHeight")
while True:
    browser.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
    time.sleep(3.0)
    new_page_height = browser.execute_script("return document.documentElement.scrollHeight")
    if new_page_height == last_page_height:
        break
    last_page_height = new_page_height
time.sleep(2)
html=browser.page_source
soup = BeautifulSoup(html, "lxml")
comment=soup.find_all('yt-formatted-string',class_ ='style-scope ytd-comment-renderer')
for i in comment:
    if i.get_text()!='''\n''':
        comment_list.append(i.get_text())
print(comment_list)
print(len(comment_list)) # 461



# 수정한 코드 설명


browser.execute_script("return document.documentElement.scrollHeight") 는 현재 띄워진 창의 총 길이를 반환한다.

즉 현재 창의 길이를 구하고, 밑으로 스크롤링을 한다.

그럼 창의 길이가 늘어나는데, 이를 그 전 창의 길이와 비교해서,

그 길이가 같다면 break를 걸어 탈출한다.

끝에 도착했다면 스크롤링해도 길이가 같으니 탈출할 수 밖에 없겠지..

이러면 댓글 수를 구하지도, 계산하지도 않아도 되니

실로 효율적이면서 놀라운 코드다.


반응형

'나 취준생 > 파이썬' 카테고리의 다른 글

합성곱 연산 알고리즘  (0) 2020.12.22
폐 사진 이미지를 숫자로 변환  (0) 2020.12.22
MYSQL, 파이썬 연동  (0) 2020.12.21
오라클과 파이썬 연동하기  (0) 2020.12.21
구글 이미지 크롤링  (0) 2020.12.18