ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [데이터 수집] selenium 유튜브 검색 결과 스크래핑
    Database/데이터 수집(Data Extraction) 2020. 12. 1. 18:00
    반응형

    유튜브 검색 결과 스크래핑


    이 글은 유튜브 검색 결과를 데이터로 수집하는 글입니다.

    유튜브 검색 결과에서 컨텐츠 제목, url 등의 가져와서 csv 파일로 저장해보았습니다. 

    열심히 배우고 있는 단계라서 실수가 있을 수도 있습니다.

    선행 개념(웹 스크래핑, 크롤링, HTML) 이해하기

    VsCode에서 작성한 코드이지만 쥬피터 노트북에서도 문제없이 작업을 했습니다. 

     

    1. 필요한 패키지 준비

    유튜브 스크래핑할 때, Beautifulsoup 사용하면 움직이는 부분(동적 페이지)은 자료가 긁어오는데 문제가 발생합니다.

    ex) 유튜브 검색 결과 페이지에서 스크롤을 끝까지 내리는 작업은 Beautifulsoup에서는 할 수가 없음

    ex) 특정 페이지를 이동하면서 자료를 가져오는 작업은 Beautifulsoup을 이용하면 잘 안됨

     

    이러한 문제는 selenium을 이용하여 브라우저 조작해서 해결 가능합니다.

    뒤로 가기, 앞으로 가기, 버튼 누르기, 스크롤 끝까지 내리기 등

     

    이 글에서는 selenium 및 webdriver 설치가 되어있다는 가정하에 진행합니다.

    설치는 여기를 참고하기

    from selenium import webdriver
    from selenium.common.exceptions import WebDriverException as WDE
    from selenium.webdriver.common.keys import Keys
    import requests
    from bs4 import BeautifulSoup
    import time
    import pandas as pd

     

    2. 유튜브 검색 후에 자료 긁어오기

    step1. 준비물 설정과 검색 접속

    • 접속할 url과 검색할 키워드를 설정하기
    • 검색 후에 스크롤을 어디까지 내릴지 설정하기
    # 접속 url
    url = "https://youtube.com/"
    
    # 검색 키워드
    keyword = "부산성형외과"
    
    # 스크롤을 어디까지 내리는지 기준 
    finish_line = 10000

     

    유튜브 홈페이지 접속

    path = 'C:/Users/admin/Desktop/Pythonworkspace/chromedriver_win32/chromedriver.exe'
    
    browser = webdriver.Chrome(path) 
    browser.maximize_window()
    
    browser.get(url)
    time.sleep(2)

     

    키워드 검색

    search = browser.find_element_by_name("search_query")
    time.sleep(2)
    search.send_keys(keyword)
    search.send_keys(Keys.ENTER)

     

    유튜브 홈페이지 접속 키워드 검색

     

    step 2. 필요한 정보 가져오기(파싱)

    유튜브 검색을 후의 url을 현재 작업창으로 만들기

    • 검색 후의 url을 'www.youtube.com/'에서 'www.youtube.com/results?search_query=부산성형외과' 변경하기
    • 이 작업을 하지 않으면 '뒤로가기', '앞으로 가기' , '스크롤 내리기' 등 작업이 검색 후의 창에서 작동하지 않음
    • 따라서 검색 후의 창을 현재 작업 창으로 바꾸는 작업을 꼭 해야 함
    present_url = browser.current_url
    browser.get(present_url)

     

    원하는 위치로 스크롤 내리기

    # 원하는 위치 스크롤 내리기  
    # finish_line = 40000 기준: 162 개
    last_page_height = browser.execute_script("return document.documentElement.scrollHeight")
    
    while True:
        # 우선 스크롤 내리기
        browser.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
        time.sleep(2.0)       # 작업 중간에 1이상으로 간격을 줘야 데이터 취득가능(스크롤을 내릴 때의 데이터 로딩 시간 때문)
        # 현재 위치 담기
        new_page_height = browser.execute_script("return document.documentElement.scrollHeight")
        
        # 과거의 길이와 현재 위치 비교하기
        if new_page_height > finish_line:
            break
        else: 
            last_page_height = new_page_height

     

    정보 가져오기

    • 지금까지 스크롤 내린 검색 창을 캡처하듯이 가져오기

    html_source = browser.page_source
    soup = BeautifulSoup(html_source, 'lxml')

     

    필요한 정보 파싱하기 

    • 가져온 자료(soup)에서 필요한 부분(컨테츠 제목, 조회수, 광고 url 등등) 가져오기

    • 검색 결과 제목(title), 채널명(name), 콘텐츠 url(content_url) 정보 파싱하기
    • 파싱 하는 법: x-path 정보 가져오는 법
      1. 가져오고 싶은 부분에 다가 [마우스 우클릭]->[검사]하기
        or [ctrl + shitf + i] 하고 원하는 부분을 선택하고 클릭
      2. 가져오고 싶은 X-path or class명 복사하기

    필요한 정보 파악하기

    • 컨텐츠마다 html 구성이 비슷하므로 첫 번째 검색 결과를 가져온 후에 나머지 전체 컨텐츠를 가져오기

     

    첫 번째 검색 결과의 제목, 채널명, url 정보 가져오기

    • find 함수: 조건에 해당하는 첫 번째 요소만 가져오기
      • find("첫 번째 컨텐츠 요소 복사", atrrs={"class":"첫 번째 컨텐츠의 class 복사"})

    • 검색 결과의 첫 번째 콘텐츠 정보만 가져와서 제목, 채널, url 정보 파싱하기
    • x-path 정보는 빨간색 프레임 참고
    # 첫 번째 컨텐츠의 제목, 채널명, url 정보 가져오기
    # 첫 번째 컨텐츠 관련 부분 html 구조 떼어내기
    # find: 해당 정보의 첫 번째 요소만 가져오기
    test = soup.find("ytd-video-renderer", attrs={"class":'style-scope ytd-item-section-renderer'})
    
    # 필요한 정보 가져오기
    title = test.find("yt-formatted-string", attrs={"class":'style-scope ytd-video-renderer'}).get_text()
    name = test.find("a", attrs={"class":'yt-simple-endpoint style-scope yt-formatted-string'}).get_text()
    content_url = test.find("a", attrs={"class":'yt-simple-endpoint style-scope ytd-video-renderer'})["href"]
    
    print(title, name, content_url)

     

    finish line까지의 검색 결과 제목, 채널명, url 정보 가져오기

    • find_all: 조건에 해당하는 모든 정보의 요소 가져오기
      • find("첫 번째 컨텐츠 요소 복사", atrrs={"class":"첫 번째 컨텐츠의 class 복사"})
    • 검색 결과의 모든 콘텐츠 정보를 가져와서 각각 제목, 채널, url 정보 파싱하기
    • 위 [필요한 정보 파악하기]의 빨간색, 파란색 프레임 참고
    # finish line까지 모든 검색 결과 정보 가져오기
    # 모든 컨텐츠 관련 부분을 떼어내기
    # find_all: 해당 정보의 모든 부분 가져오기
    elem = soup.find_all("ytd-video-renderer", attrs={"class":'style-scope ytd-item-section-renderer'})
    
    # 필요한 정보 가져오기
    df = []
    for t in elem:
        title = t.find("yt-formatted-string", attrs={"class":'style-scope ytd-video-renderer'}).get_text()
        name = t.find("a", attrs={"class":'yt-simple-endpoint style-scope yt-formatted-string'}).get_text()
        content_url = t.find("a", attrs={"class":'yt-simple-endpoint style-scope ytd-video-renderer'})["href"]
        df.append([name, title , 'https://www.youtube.com/'+content_url])

    * 주의사항

    제목, 이름, 콘텐츠 정보를 가져올 때(파싱 할 때), 위 코드대로 안 될 수도 있습니다. 홈페이지 구성이 바뀌면 다시 구성 요소를 따서 해야 합니다.   

     

    3. 데이터 저장하기

    데이터 확인하기

     

    데이터 저장하기

    • 데이터를 담을 공간인 새로운 데이터 프레임 만들기(new)
    • 데이터 저장할 때는 컬럼 정보도 꼭 저장하기 
    ## 자료 저장
    # 데이터 프레임 만들기
    new = pd.DataFrame(columns=['name', 'title' , 'url_link'])
    
    # 자료 집어넣기
    for i in range(len(df)):
        new.loc[i] = df[i]
    
    # 저장하기
    # 현재 작업폴더 안의 data 폴더에 저장
    df_dir = "./data/" # 저장할 디렉토리
    new.to_csv(df_dir+"Youtube_search_df.csv", index=False, encoding='utf8')
    
    ## 컬럼 정보 저장
    # 컬럼 설명 테이블
    col_names = ['name', 'title' ,'url_link']
    col_exp = ['컨텐츠 올린 채널명', '컨텐츠 제목', '연결 링크']
    
    new_exp = pd.DataFrame({'col_names':col_names,
                            'col_explanation':col_exp})
    
    # 현재 작업폴더 안의 data 폴더에 저장
    df_dir = "./data/" # 저장할 디렉토리
    new_exp.to_csv(df_dir+"Youtube_col_exp.csv", index=False, encoding='utf8')
    
    # 브라우저 닫기
    browser.close()

     

    반응형

    댓글

Designed by Tistory.