Recent Posts
Recent Comments
Archives
반응형
250x250
«   2024/04   »
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
Today
Yesterday

Total
04-24 00:42
관리 메뉴

Hey Tech

[Python] 유튜브 콘텐츠 크롤러 코드 Version 1.0.1 본문

AI & 빅데이터/데이터 엔지니어링

[Python] 유튜브 콘텐츠 크롤러 코드 Version 1.0.1

Tony Park 2022. 3. 7. 23:50
728x90
반응형

📝 목차

Update Log
1.  주요 기능
2. 크롬 설치
3. 전체 코드
4. 패키지 설치
5. 코드 설명

🛠 Update Log

👏 Version 1.0.1 @ 2022-10-11

(1) 콘텐츠 조회수 및 업로드일 추출 로직 추가

Heo Jin 님 요청사항으로 추가 및 테스트 완료하였습니다.

1. 주요 기능

본 포스팅에서는 유튜브 검색 결과 콘텐츠의 정보를 수집하는 Scraper를 개발합니다.

※ Scrap이란?('더보기' 클릭)

더보기

Scrap[스크랩]은 웹 페이지에서 특정 데이터를 가져오는 행동을 말합니다.

이처럼 Data Scraping을 하는 프로그램을 Data Scraper 또는 Web Scraper라고 부릅니다.

유튜브 내 특정 검색 결과의 콘텐츠를 자동 탐색하는 모습

(1) 수집 데이터 종류

- 콘텐츠 제목
- 콘텐츠 링크

- 조회수

- 업로드 일자(=현재 시간 기준 업로드 경과일)

2) 데이터 프레임 포맷팅

데이터 Scrap 결과

2. 크롬 설치

※ 이 코드는 크롬에서만 동작합니다.

크롬 브라우저가 설치되어 있지 않다면 이곳을 클릭하셔서 미리 다운로드하여 주시길 바랍니다.

3. 전체 코드

전체 코드는 아래 링크(Github)에 업로드하였습니다.

src 폴더 내 주피터 노트북 파일에서 작업하였습니다.

전체 코드를 다운로드하여 주시길 바랍니다.
https://github.com/park-gb/youtube-content-scaper.git

 

GitHub - park-gb/youtube-content-scaper: 유튜브 내 검색 결과의 콘텐츠 정보 추출 Scraper

유튜브 내 검색 결과의 콘텐츠 정보 추출 Scraper. Contribute to park-gb/youtube-content-scaper development by creating an account on GitHub.

github.com

4. 패키지 설치

코드 실행 전에 몇 가지 패키지를 설치해야 하며, 활용한 패키지 정보는 다음과 같습니다.

bs4==0.0.1
selenium==4.1.2
webdriver-manager==3.5.3
pandas==1.4.1
numpy==1.22.2

2가지 패키지 설치 방법을 제안해 드립니다.

방법 1. pipenv 활용(권장)

저는 파이썬에서 공식적으로 권장하는 가상환경 모듈인 pipenv을 활용하여 작업하였습니다. pipenv는 virtualenv, venv 등의 가상환경 모듈보다 훨씬 강력한 기능과 편의성을 제공하기 때문에, 가상환경 모듈을 사용하신다면 pipenv 사용을 추천합니다.

Github에서 다운받은 폴더 내 Pipfile 파일에 패키지 정보가 모두 저장되어 있습니다. 따라서 pipenv를 사용하신다면 아래 명령어 한 줄이면 필요한 모든 패키지를 버전까지 고려하여 자동으로 설치해 줍니다.

pipenv install

pipenv 사용방법 관련해서는 이곳에 자세히 정리해 두었으니 참고해 주시길 바랍니다.

방법 2. pip 활용

사용한 패키지를 일일이 다운로드하는 방법도 있습니다.

$ pip install bs4==0.0.1
$ pip install selenium==4.1.2
$ pip install webdriver-manager==3.5.3
$ pip install pandas==1.4.1
$ pip install numpy==1.22.2

5. 코드 설명

전체 코드는 Github에 업로드 했으니 누구나 다운로드하실 수 있습니다. 작업 프로세스나 코드에 부연설명이 필요하신 분들은 참고하시길 바랍니다.

1) 패키지 Import

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from webdriver_manager.chrome import ChromeDriverManager
from bs4 import BeautifulSoup
import time
import random
import pandas as pd

필요한 패키지를 설치하고 import 합니다.

# 최신 크롬 드라이버 사용하도록 세팅: 현재 OS에 설치된 크롬 브라우저 버전에 맞게 cache에 드라이버 설치
from selenium.webdriver.chrome.service import Service
service = Service(ChromeDriverManager().install())

크롬을 프로그램을 통해 제어하기 위해서는 크롬 드라이버가 필요합니다. 크롬 드라이버를 현재 PC에서 사용 중인 크롬 브라우저 버전에 맞는 파일을 다운로드하여 사용할 수도 있습니다. 하지만, 크롬 버전을 확인하고 이에 맞는 크롬 드라이버를 찾아 다운로드하여야 하기 때문에 번거로운 작업입니다.
Webdriver manager 패키지 내 Service 모듈은 현재 PC에서 사용 중인 크롬 브라우저 버전에 맞는 크롬 드라이버를 캐시에 저장하여 활용할 수 있도록 지원합니다. 크롬 드라이버 버전 호환의 간편함뿐만 아니라 크롬 드라이버를 직접 설치할 필요가 없다는 점이 큰 장점입니다.

2) 무한 스크롤 함수

def scroll():
    try:        
        # 페이지 내 스크롤 높이 받아오기
        last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
        while True:
            # 임의의 페이지 로딩 시간 설정
            # PC환경에 따라 로딩시간 최적화를 통해 scraping 시간 단축 가능
            pause_time = random.uniform(1, 2)
            # 페이지 최하단까지 스크롤
            driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
            # 페이지 로딩 대기
            time.sleep(pause_time)
            # 무한 스크롤 동작을 위해 살짝 위로 스크롤(i.e., 페이지를 위로 올렸다가 내리는 제스쳐)
            driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight-50)")
            time.sleep(pause_time)
            # 페이지 내 스크롤 높이 새롭게 받아오기
            new_page_height = driver.execute_script("return document.documentElement.scrollHeight")
            # 스크롤을 완료한 경우(더이상 페이지 높이 변화가 없는 경우)
            if new_page_height == last_page_height:
                print("스크롤 완료")
                break
                
            # 스크롤 완료하지 않은 경우, 최하단까지 스크롤
            else:
                last_page_height = new_page_height
            
    except Exception as e:
        print("에러 발생: ", e)

유튜브 웹 페이지는 스크롤을 해야 새로운 콘텐츠 정보를 제공하기 때문에, 모든 검색 결과를 확인하기 위해서는 반드시 무한 스크롤 기능이 필요합니다. 페이지 로딩을 일정 시간 동안 기다리며 스크롤이 불가할 때까지 무한 반복하여 스크롤하는 함수입니다.

3) 데이터 Scrap

검색 키워드 설정

# 검색 키워드 설정: 키워드 내 띄어쓰기는 URL에서 '+'로 표시되기 때문에 이에 맞게 변환
SEARCH_KEYWORD = '잭 니콜라스 GC'.replace(' ', '+')

유튜브에서 검색할 키워드를 입력합니다. 해당 검색어는 드라이버에서 접근할 URL에 활용됩니다. 유튜브의 경우, 검색어 내 띄어쓰기를 URL에서 + 기호로 표현한다는 점에서, replace 함수를 활용해 띄어쓰기를 자동으로 +로 변환하는 로직을 활용하였습니다. 저는 예시로 잭 니콜라스 Golf Club 관련 콘텐츠를 검색해 보고자 했습니다.

드라이버 세팅 및 실행

driver = webdriver.Chrome(service=service)
# 스크래핑 할 URL 세팅
URL = "https://www.youtube.com/results?search_query=" + SEARCH_KEYWORD
# 크롬 드라이버를 통해 지정한 URL의 웹 페이지 오픈
driver.get(URL)
# 웹 페이지 로딩 대기
time.sleep(3)
# 무한 스크롤 함수 실행
scroll()

크롬 드라이버를 변수에 할당하고, 유튜브 웹 페이지에서 키워드 검색 시 활용하는 URL 구조와 검색어를 조합합니다. 드라이버로 조합한 URL에 접근합니다. 일정 시간 페이지 로딩이 지나면 무한 스크롤 함수를 실행합니다.

페이지 소스 추출

# 페이지 소스 추출
html_source = driver.page_source
soup_source = BeautifulSoup(html_source, 'html.parser')

페이지 소스를 추출합니다.

4) 데이터 추출

# 콘텐츠 모든 정보
content_total = soup_source.find_all(class_ = 'yt-simple-endpoint style-scope ytd-video-renderer')
# 콘텐츠 제목만 추출
content_total_title = list(map(lambda data: data.get_text().replace("\n", ""), content_total))
# 콘텐츠 링크만 추출
content_total_link = list(map(lambda data: "https://youtube.com" + data["href"], content_total))

#--------조회수 & 업로드 날짜 추출(Updated at 2022-10-11)--------#
content_record_src = soup_source.find_all(class_ = 'style-scope ytd-video-meta-block')
content_view_cnt = [content_record_src[i].get_text().replace('조회수 ', '') for i in range(5, len(content_record_src), 10)]
content_upload_date = [content_record_src[i].get_text() for i in range(6, len(content_record_src), 10)]
#---------------------------------------------------------#

# 딕셔너리 포맷팅
content_total_dict = {'title'       : content_total_title, 
                      'link'        : content_total_link, 
                      'view'        : content_view_cnt,
                      'upload_date' : content_upload_date
                     }

페이지 소스에서 콘텐츠와 관련된 데이터를 추출하여 content_total 변수에 저장하고 제목과 링크를 추출합니다.

다음으로 조회수와 업로드일자를 추출합니다.

추출한 데이터는 딕셔너리 형태로 포맷팅 합니다.

5) 데이터 프레임 포맷팅

df = pd.DataFrame(content_total_dict)
df

딕셔너리 기반의 데이터는 2차원 데이터 프레임으로 포맷팅 하고, 데이터 상태를 확인합니다.

데이터 Scrap 결과

6) 데이터 저장

df.to_csv("../data/content_total.csv", encoding='utf-8-sig')

데이터가 잘 추출되었으니 로컬인 data 폴더에 저장합니다.

📝 참고할 만한 포스팅

1. Python 기반 유튜브 콘텐츠 Scraper V.1.0.1
2. [Python] 인스타그램 데이터 크롤러 코드 공유 Version 1.0
3. [Python] 구글 플레이 스토어 웹 크롤러 코드 Version2
4. [Python] pipenv 등장배경, 설치, 패키지 관리 방법



포스팅 내용에 오류가 있거나, 코드 리뷰, 피드백, 질문 모두 대환영입니다.

아래에 👇👇👇 댓글 남겨주시면 감사드리겠습니다 :)
그럼 오늘도 즐겁고 건강한 하루 보내시길 바랍니다.
고맙습니다 :D

728x90
반응형
Comments