본문 바로가기
  • 실행력이 모든걸 결정한다
Crawling

[크롤링, 예제 4] Youtube - 필터를 적용하여 영상 목록 보기

by 김코더 김주역 2020. 11. 2.
반응형

동적 크롤링 첫 번째 시간이다

웹 페이지 내에서 특정 요소를 클릭할 때, url는 변하지 않지만 html코드가 변할 수 있다.

예를 들면, 유튜브 검색 목록에서 filter 버튼을 클릭하거나, 댓글 목록에서 스크롤을 내려서 더 많은 댓글을 로드할 때가 위에 언급한 경우에 해당 되는데, 이런 때에는 selenium과 driver을 이용하여 동적 크롤링을 해줘야 한다.

 

이번 포스팅은 예제 1~3과는 많이 다를 것이므로 더 주의 깊게 보는 것을 권장한다.

 

0. 크롤링 계획 세우기

유튜브 영상 검색과 필터 적용까지 자동화 할 것이다.

필터는 크리에이티브 커먼즈, 조회수를 적용할 것이다.

크리에이티브 커먼즈는 출처만 남긴다면 재사용이 가능한 영상을 의미한다. 개발자나 영상 편집자들은 주목해야 하는 기준이다. 이 크리에이티브 커먼즈 영상들을 조회수 순으로 정렬하고, 잘 정렬되었는지 확인하기 위해 영상 별 조회수를 위에서 부터 콘솔창에 출력한다.

 

<적용 완료된 모습>

자세히 보면 적용된 필터 옵션의 텍스트가 더 까맣다.

 

 

1. 크롤링할 페이지 접속

Youtube에 접속한다.

https://www.youtube.com 

 

YouTube

© 2020 Google LLC 회사명: Google LLC CEO: Sundar Pichai 주소: 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA. 전화: 080-822-1450 (무료)

www.youtube.com

 

2. 크롤링 가능 여부 확인(필수)

 

Youtube 메인 화면에서 영상을 검색하면 /results로 이동하는데 Disallow에 /results가 있다.

아래 코드를 응용하거나 실행하지 말고 눈으로 간단히 동적 크롤링의 원리만 이해하는 것을 권장한다.

정확한 기준을 파악하기 위해 여러 크롤링 관련 판결 사례들을 검색해봤는데 해당 사이트 회사 매출에 타격을 주지 않으면서, 상업적 이용을 하지 않는다면 크게 문제 되지 않고, 개인적 학습용으로 실행해 보는 것은 괜찮을 것으로 보인다.

그러나 이것은 본인의 개인적 견해일 뿐이고 크롤링 합/불법 여부에 대한 정확한 기준은 복잡하기 때문에 눈으로만 보는것이 제일 안전하다.

본인도 이 코드는 실행하지 않았지만 무조건 제대로 동작할 것이다. 아무튼 그렇다.

 

 

3. 크롤링할 대상 결정

검색창에 아무거나 입력 하면 /results 로 이동하게 되는데

필터를 누르면 이렇게 27종류의 필터 옵션들이 나온다.

여기서 필터를 눌러도 url은 바뀌지 않는다.

 

 

1~4 숫자들은 클릭 순서이다.

먼저 필터를 누르고 크리에이티브 커먼즈를 클릭하면 url이 바뀌면서, 크리에이티브 커먼즈가 표시되어 있는 영상들 목록만 나오게 된다. 필터 자체를 누르는 것으로는 url이 바뀌지 않지만, 필터를 눌렀을 때 나오는 27가지 필터 옵션을 누르면 url이 바뀌게 된다.

그 후 필터를 다시 눌러서 조회수를 클릭하면 두 기준이 모두 적용이 된다.

그래서 필터에 클릭 순서 1,3을 적어둔 것이다.

 

<조회수 정보>

 

 

4. 크롤링할 데이터가 있는 태그 파악

 

<검색창 - input 태그>

 

 

<필터 토글 버튼 - a 태그>

 

 

<필터 옵션 - a 태그>

 

- 크리에이티브 커먼즈

 

 

- 조회수

 

 

<조회수 정보>

 

5. 태그 규칙 파악

 

검색창 :  name이 'search_query'인 유일한 <input> 태그이다. 

 

검색 버튼, 필터 토글 버튼 : Chrome 브라우저에서 해당 태그의 웹코드에서 우클릭 해서 나오는 Copy -> Copy XPath 로 xpath를 복사 할 수 있는데, tag, id, class 외에도 xpath로 요소를 찾을 수도 있다. 참고로, Copy full XPath를 이용해도 좋다.

 

 

필터 옵션 : 두 필터 옵션은 id가 collapse-content인 요소에서 각각 4번째 <ytd-search-group-renderer> 태그 안에 있는 / 5번째 <ytd-search-filter-renderer> 와, 5번째 <ytd-search-group-renderer> 태그 안에 있는 / 3번째 <ytd-search-filter-renderer> 태그 안에서, <a> 태그 형태로 존재한다. 

 

<참고 사진>

(크리에이티브 커먼즈로 예를 들어, 4번째 <ytd-search-group-renderer> 인 '기능별' 필터 그룹 옵션에서 5번째 <ytd-search-filter-renderer> 인 '크리에이티브 커먼즈' 필터 옵션이 있다.)

   

조회수 정보 :  원하는 데이터들은 <ytd-video-renderer> 태그 안에 있는 / id가 'metadata-line'인 <div> 태그 안에 있는 / 1번째 <span> 태그마다 text 형태로 존재한다. (<ytd-video-renderer> 태그를 고려하지 않으면 맨 위에 가끔 나타나는 광고 영상의 조회수까지 콘솔에 출력되기 때문에 보기 안좋아질 것이다.) 

 

6. 코딩

 

중간에 0.5초씩 sleep함수를 이용해 동작마다 코드 수행을 지연시키는 이유는 웹 사이트에 모든 요소가 모두 로드 될 때 까지 기다려주기 위함이다. 이 지연 함수를 넣지 않으면 웹 사이트에 요소가 로드 되기도 전에 요소를 찾게 되어 오류가 날수도 있다.

위에서 설명한 모든 동작은 주석으로 달아 놓았다.

 

from selenium import webdriver
from time import sleep
from bs4 import BeautifulSoup
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--start-maximized') #전체 화면으로 크롬 브라우저 실행
driver = webdriver.Chrome('C:\chromedriver\chromedriver.exe',chrome_options=chrome_options)
driver.get('https://www.youtube.com')
keyword = '여러분들이 원하는 검색 키워드'

#검색창 요소 선택
search_bar = driver.find_element_by_name("search_query")

#검색창에 text 입력
search_bar.send_keys(keyword)

#검색 실행 버튼 클릭
driver.find_element_by_xpath('//*[@id="search-icon-legacy"]').click()
sleep(0.5)

#필터 토글 버튼 클릭
driver.find_element_by_xpath('//*[@id="container"]/ytd-toggle-button-renderer/a').click()
sleep(0.5)

#크리에이티브 커먼즈 필터 옵션 클릭
driver.find_element_by_css_selector("#collapse-content ytd-search-filter-group-renderer:nth-child(4) ytd-search-filter-renderer:nth-of-type(5) a").click()
sleep(0.5)

#다시 필터 토글 버튼 클릭
driver.find_element_by_xpath('//*[@id="container"]/ytd-toggle-button-renderer/a').click()
sleep(0.5)

#조회수 필터 옵션 클릭
driver.find_element_by_css_selector("#collapse-content ytd-search-filter-group-renderer:nth-child(5) ytd-search-filter-renderer:nth-of-type(3) a").click()
sleep(0.5)

#정렬된 조회수 정보들을 모아서 콘솔창에 출력
views = driver.find_elements_by_css_selector("ytd-video-renderer #metadata-line span:first-child")
for view in views:
    print(view.text)

 

7. 실행

문제가 될 수 있기 때문에 실행은 생략

그래도 실행 결과 정도는 예상해볼 수 있다.

 

조회수 a회
조회수 b회
조회수 c회
조회수 d회
...

# a ≥ b ≥ c ≥ d

 

 

 

반응형

댓글