ch0nny_log

[빅데이터분석] Python_41. 파이썬 웹 스크롤링 (youtube text) 본문

빅데이터 분석(with 아이티윌)/python

[빅데이터분석] Python_41. 파이썬 웹 스크롤링 (youtube text)

chonny 2024. 8. 26. 18:02
관련 키워드가 뭐가 있는지?
관련 언급 단어들이 뭐가 있는지?
반응이 긍정적인지 부정적인지 감정 분석 수행

 

※ 생성할 함수 3가지
1. get_url_youtube : 해당 티워드로 검색한 상세 url을 가져옴
2. youtube_page_html_source : 상세 url을 넣고 html 코드를 받아오는 함수
3. get_comments : 상세 url html 코드에서 댓글을 전부 수집하는 함수
## 유튜브 text 웹 크롤링


# 1. 첫번째 함수(키워드를 입력하면 해당 영상의 상세 url 을 가져오는 함수)

#1. 필요한 패키지 임폴트
import  requests
import urllib.request
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys 
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service 
from webdriver_manager.chrome import ChromeDriverManager
import  pandas  as  pd

#2. 키워드를 입력하면 해당 영상의 상세 url 을 가져오는 함수

def  get_url_youtube(keyword):
    titles = []  #유튜브 영상 제목을 담을 리스트
    urls = []    #키워드를 넣었을때 나오는 모든 영상들의 url 주소를 담기 위한 리스트

    # 입력한 키워드를 컴퓨터가 알아들을 수 있는 언어도 인코딩합니다.
    search_keyword_encode = requests.utils.quote(keyword)

    # 유튜브에서 해당 키워드의 영상 리스트를 찾을 수 있는 url 을 만들어서 url변수에 입력
    url = "https://www.youtube.com/results?search_query=" + search_keyword_encode

    # 크롬 로봇을 지정합니다.
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service)

    # 크롬 로봇이 url 을 직접 열게 합니다.
    driver.get(url)

    # 키워드로 받아온 영상 리스트 웹페이지의 처음부터 맨 마지막까지의 높이를 추출합니다
    last_page_height = driver.execute_script("return document.documentElement.scrollHeight")

    while True:  #   아래의 실행문이 무한히 반복될 수 있게 합니다.

        # 마우스 스크롤을 끝까지 내리게 합니다.
        driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")

        time.sleep(3)

        # 마우스 스크롤을 내리는 데까지의 높이를 추출합니다
        new_page_height = driver.execute_script("return document.documentElement.scrollHeight")

        # 지금의 높이가 웹페이지의 끝이라면
        if  new_page_height == last_page_height:
            break  # 무한 루프 종료해라 !

        # new_page_height 의 값을 last_page_height 에 할당
        last_page_height = new_page_height
    
    html_source = driver.page_source  # 페이지의 html 소소를 html_source 에 담습니다.
    driver.quit() # 브라우져를 닫습니다.

    # html 코드를 뷰티플 스프로 파싱합니다.
    soup = BeautifulSoup( html_source, 'lxml') 

    # 영상 제목과 상세 url 가져오기 
    datas = soup.select("a#video-title")
    for  i  in  datas:
        title =  i.get('title') 
        url = "https://www.youtube.com/" + i.get("href")
        if title:
            titles.append(title)
            urls.append(url)
    
    return  titles, urls

title, url = get_url_youtube('영국 관광지')
print(len(title))
print(len(url))


# 2. 두번째 함수(상세 url 을 가져와서 해당 페이지의 html 코드를 출력하는 함수)

#1. 필요한 패키지 임폴트
import  requests
import urllib.request
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys 
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service 
from webdriver_manager.chrome import ChromeDriverManager
import  pandas  as  pd

#2. 상세 url 을 넣고 html 을 받아오는 코드

def  youtube_page_html_source(keyword):
    
    title, url = get_url_youtube(keyword)
    
    html_sources = [] # html 코드를 저장하기 위한 리스트를 생성합니다. 

    # 크롬 로봇을 지정합니다.
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service)

    for  i  in  range(0, 2): # 전체 url 말고 2개의 url 만 가져옵니다. 
        
        # 크롬 로봇이 url 을 직접 열게 합니다.
        driver.get(url[i])
    
        # 키워드로 받아온 영상 리스트 웹페이지의 처음부터 맨 마지막까지의 높이를 추출합니다
        last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
    
        while True:  #   아래의 실행문이 무한히 반복될 수 있게 합니다.
    
            # 마우스 스크롤을 끝까지 내리게 합니다.
            driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
    
            time.sleep(3)
    
            # 마우스 스크롤을 내리는 데까지의 높이를 추출합니다
            new_page_height = driver.execute_script("return document.documentElement.scrollHeight")
    
            # 지금의 높이가 웹페이지의 끝이라면
            if  new_page_height == last_page_height:
                break  # 무한 루프 종료해라 !
    
            # new_page_height 의 값을 last_page_height 에 할당
            last_page_height = new_page_height

        time.sleep(5)
        html_source = driver.page_source  # 페이지의 html 소소를 html_source 에 담습니다.
        time.sleep(5)

        html_sources.append(html_source)
        print('OK')

    driver.quit()
        
    return  html_sources


# 3. 세번째 함수(글쓴이와 댓글을 가져오는 함수) + csv 파일로 저장

# 글쓴이와 뎃글 가져오는 함수

def get_comments(html_sources):
    # 상세 url 마다 담길 뎃글의 데이터 프레임을 위한 리스트
    my_dataframes=[]
    cnt = 0 
    while  cnt <  len(html_sources):
        html = html_sources[cnt]
        cnt += 1
        soup = BeautifulSoup(html, 'lxml')

        # 글쓴이 가져오기 
        writer = soup.select('div#header-author > h3 > a > span')
        # 댓글 가져오기
        comments = soup.select('yt-attributed-string#content-text > span')

        # 글쓴이와 댓글의 길이가 다를 경우에 예외처리 
        min_len = min( len(writer), len(comments) )

        if  min_len == 0:
            continue

        #글쓴이 데이터를 writer2 리스트에 추가합니다. 
        writer2 = []
        for  i  in range(min_len):
            str_temp = str(writer[i].text).strip()  
            writer2.append(str_temp)

        # 뎃글 데이터를 comments2 리스트에 추가합니다. 
        comments2 = []
        for  i  in range(min_len):
            str_temp2 = str(comments[i].text).strip()
            comments2.append(str_temp2)

        # 글쓴이와 뎃글 데이터로 판다스 데이터 프레임을 생성
        pd_data = {"id" : writer2, "comment" : comments2 }
        pd_df = pd.DataFrame(pd_data)

        # 판다스 데이터 프레임을 my_dataframes 리스트에 append 시킴
        if not  pd_df.empty:
            my_dataframes.append(pd_df)

    # 글쓴이와 뎃글을 가지고 판다스 데이터 프레임을 생성하기
    if my_dataframes:
        comments_df = pd.concat( my_dataframes, ignore_index=True)
    else:
        comments_df = pd.DataFrame(columns=['id','comment'])

    return  comments_df
        

#my_data = get_comments(kkk)
#my_data.to_csv('c:\\data\\youtube.csv', index=False, encoding="utf-8")


# 4. 네번째 함수 (키워드의 유튜브 댓글이 수집되는 함수)

# 키워드를 입력해서 해당 키워드의 유튜브 뎃글이 수집되는 함수를 생성하시오

def scroll_youtube(keyword):
    title, url = get_url_youtube(keyword)
    kkk = youtube_page_html_source(url)
    my_data=get_commets(kkk)
    my_data.to_csv(f'c:\\data\\{keyword}_youtube.csv', index =False , encoding ="utf-8")

scroll_youtube('저출산')


★ 총코드

## 유튜브 text 웹 크롤링

#1. 필요한 패키지 임폴트
import  requests
import urllib.request
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys 
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service 
from webdriver_manager.chrome import ChromeDriverManager
import  pandas  as  pd

#2. 키워드를 입력하면 해당 영상의 상세 url 을 가져오는 함수

def  get_url_youtube(keyword):
    titles = []  #유튜브 영상 제목을 담을 리스트
    urls = []    #키워드를 넣었을때 나오는 모든 영상들의 url 주소를 담기 위한 리스트

    # 입력한 키워드를 컴퓨터가 알아들을 수 있는 언어도 인코딩합니다.
    search_keyword_encode = requests.utils.quote(keyword)

    # 유튜브에서 해당 키워드의 영상 리스트를 찾을 수 있는 url 을 만들어서 url변수에 입력
    url = "https://www.youtube.com/results?search_query=" + search_keyword_encode

    # 크롬 로봇을 지정합니다.
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service)

    # 크롬 로봇이 url 을 직접 열게 합니다.
    driver.get(url)

    # 키워드로 받아온 영상 리스트 웹페이지의 처음부터 맨 마지막까지의 높이를 추출합니다
    last_page_height = driver.execute_script("return document.documentElement.scrollHeight")

    while True:  #   아래의 실행문이 무한히 반복될 수 있게 합니다.

        # 마우스 스크롤을 끝까지 내리게 합니다.
        driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")

        time.sleep(3)

        # 마우스 스크롤을 내리는 데까지의 높이를 추출합니다
        new_page_height = driver.execute_script("return document.documentElement.scrollHeight")

        # 지금의 높이가 웹페이지의 끝이라면
        if  new_page_height == last_page_height:
            break  # 무한 루프 종료해라 !

        # new_page_height 의 값을 last_page_height 에 할당
        last_page_height = new_page_height
    
    html_source = driver.page_source  # 페이지의 html 소소를 html_source 에 담습니다.
    driver.quit() # 브라우져를 닫습니다.

    # html 코드를 뷰티플 스프로 파싱합니다.
    soup = BeautifulSoup( html_source, 'lxml') 

    # 영상 제목과 상세 url 가져오기 
    datas = soup.select("a#video-title")
    for  i  in  datas:
        title =  i.get('title') 
        url = "https://www.youtube.com/" + i.get("href")
        if title:
            titles.append(title)
            urls.append(url)
    
    return  titles, urls


#1. 필요한 패키지 임폴트
import  requests
import urllib.request
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys 
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service 
from webdriver_manager.chrome import ChromeDriverManager
import  pandas  as  pd

#2. 상세 url 을 넣고 html 을 받아오는 코드

def  youtube_page_html_source(keyword):
    
    title, url = get_url_youtube(keyword)
    
    html_sources = [] # html 코드를 저장하기 위한 리스트를 생성합니다. 

    # 크롬 로봇을 지정합니다.
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service)

    for  i  in  range(0, 20): # 전체 url 말고 2개의 url 만 가져옵니다. 
        
        # 크롬 로봇이 url 을 직접 열게 합니다.
        driver.get(url[i])
    
        # 키워드로 받아온 영상 리스트 웹페이지의 처음부터 맨 마지막까지의 높이를 추출합니다
        last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
    
        while True:  #   아래의 실행문이 무한히 반복될 수 있게 합니다.
    
            # 마우스 스크롤을 끝까지 내리게 합니다.
            driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
    
            time.sleep(3)
    
            # 마우스 스크롤을 내리는 데까지의 높이를 추출합니다
            new_page_height = driver.execute_script("return document.documentElement.scrollHeight")
    
            # 지금의 높이가 웹페이지의 끝이라면
            if  new_page_height == last_page_height:
                break  # 무한 루프 종료해라 !
    
            # new_page_height 의 값을 last_page_height 에 할당
            last_page_height = new_page_height

        time.sleep(5)
        html_source = driver.page_source  # 페이지의 html 소소를 html_source 에 담습니다.
        time.sleep(5)

        html_sources.append(html_source)
        print('OK')

    driver.quit()
        
    return  html_sources 

# 글쓴이와 뎃글 가져오는 함수

def get_comments(html_sources):
    # 상세 url 마다 담길 뎃글의 데이터 프레임을 위한 리스트
    my_dataframes=[]
    cnt = 0 
    while  cnt <  len(html_sources):
        html = html_sources[cnt]
        cnt += 1
        soup = BeautifulSoup(html, 'lxml')

        # 글쓴이 가져오기 
        writer = soup.select('div#header-author > h3 > a > span')
        # 댓글 가져오기
        comments = soup.select('yt-attributed-string#content-text > span')

        # 글쓴이와 댓글의 길이가 다를 경우에 예외처리 
        min_len = min( len(writer), len(comments) )

        if  min_len == 0:
            continue

        #글쓴이 데이터를 writer2 리스트에 추가합니다. 
        writer2 = []
        for  i  in range(min_len):
            str_temp = str(writer[i].text).strip()  
            writer2.append(str_temp)

        # 뎃글 데이터를 comments2 리스트에 추가합니다. 
        comments2 = []
        for  i  in range(min_len):
            str_temp2 = str(comments[i].text).strip()
            comments2.append(str_temp2)

        # 글쓴이와 뎃글 데이터로 판다스 데이터 프레임을 생성
        pd_data = {"id" : writer2, "comment" : comments2 }
        pd_df = pd.DataFrame(pd_data)

        # 판다스 데이터 프레임을 my_dataframes 리스트에 append 시킴
        if not  pd_df.empty:
            my_dataframes.append(pd_df)

    # 글쓴이와 뎃글을 가지고 판다스 데이터 프레임을 생성하기
    if my_dataframes:
        comments_df = pd.concat( my_dataframes, ignore_index=True)
    else:
        comments_df = pd.DataFrame(columns=['id','comment'])

    return  comments_df
        

#my_data = get_comments(kkk)
#my_data.to_csv('c:\\data\\youtube.csv', index=False, encoding="utf-8")


# 키워드를 입력해서 해당 키워드의 유튜브 뎃글이 수집되는 함수를 생성하시오

def  scroll_youtube(keyword):
  
    kkk = youtube_page_html_source(keyword)
    my_data = get_comments(kkk)
    my_data.to_csv(f'c:\\data\\{keyword}_youtube.csv', index=False, encoding="utf-8")

 

저출산_youtube.csv
2.57MB





 


+ 저장된 이미지가 하얗게 나오는 현상 수정

 

★ 총코드 (보은님.ver)

# 다음 이미지 스크롤링 함수 

# 1. 필요한 패키지 임포트 
import urllib.request
from bs4 import BeautifulSoup
from selenium import webdriver
from seleniuhttp://m.webdriver.common.keys import Keys 
import time
from seleniuhttp://m.webdriver.common.by import By
from seleniuhttp://m.webdriver.chrome.service import Service 
from webdriver_manager.chrome import ChromeDriverManager



# 2. 크롬 드라이버의 위치 지정후 driver 객체를 생성
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

# 3. 구글 이미지 검색 페이지로 이동
driver.get("https://search.daum.net/search?w=img")

# 4. 검색창 객체 생성
search = driver.find_element(By.XPATH, '//*[@id="q"]')      

# 5. 검색어 입력
name = "백구"
search.send_keys(name)

# 6. 엔터 입력
search.submit()



# 7. 스크롤을 아래로 내려서 이미지를 더 로드
# 키워드로 받아온 영상 리스트 웹페이지의 처음부터 맨 마지막까지의 높이를 추출합니다
last_page_height = driver.execute_script("return document.documentElement.scrollHeight")

while True:  #   아래의 실행문이 무한히 반복될 수 있게 합니다.
    # 마우스 스크롤을 끝까지 내리게 합니다.
    driver.find_element(By.XPATH, "//body").send_keys(Keys.END) 
    time.sleep(1)
    # 마우스 스크롤을 내리는 데까지의 높이를 추출합니다
    new_page_height = driver.execute_script("return document.documentElement.scrollHeight")
    # 지금의 높이가 웹페이지의 끝이라면
    if  new_page_height == last_page_height:
        break  # 무한 루프 종료해라 !
    # new_page_height 의 값을 last_page_height 에 할당
    last_page_height = new_page_height
    print(last_page_height)




# 현재 페이지의 HTML 코드를 가져옴
html = driver.page_source
soup = BeautifulSoup(html, "lxml")

# 이미지 URL들을 params 리스트에 담기
params_d = []
imgList = soup.find_all("div", class_="wrap_thumb")  #imageColl > div.cont_img > div > div.list_row > div:nth-child(1314)



for d_img in imgList:
    img_tag = d_img.find("img")  # d-img 태그 내의 a 태그를 찾음
    if img_tag:
        img_url = img_tag.get("src")
        print(img_url)
        params_d.append(img_url)

print(params_d)


★ 총코드 (지님.ver)

def download_daum_image(keyword):
    # 1. 패키지를 임포트
    import urllib.request
    from bs4 import BeautifulSoup
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys 
    import time
    from selenium.webdriver.common.by import By
    from selenium.webdriver.chrome.service import Service 
    from webdriver_manager.chrome import ChromeDriverManager
    import requests
    from urllib.parse import urljoin
    import os
    
    # 2. 크롬 드라이버의 위치 지정후 driver 객체를 생성
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service)
    
    # 3. Daum 이미지 검색 페이지로 이동
    driver.get("https://search.daum.net/search?w=img&nil_search=btn&DA=NTB&enc=utf8&q=")
    
    # 4. 검색창 객체 생성
    search = driver.find_element(By.XPATH, '//*[@id="q"]')
    
    # 5. 검색어 입력
    name = keyword
    search.send_keys(name)
    
    # 6. 엔터 입력
    search.submit()
    
    # 7. 스크롤을 아래로 내려서 이미지를 더 로드
    for i in range(1, 50):
        driver.find_element(By.XPATH, "//body").send_keys(Keys.END) 
        time.sleep(4)  # 스크롤 후 충분한 시간 기다리기

    # 8. 현재 페이지의 HTML 코드를 가져옴
    html = driver.page_source
    soup = BeautifulSoup(html, "lxml")
    
    # 9. 이미지 URL들을 params 리스트에 담기
    params_g = []
    imgList = soup.find_all("div", class_="wrap_thumb")
    
    for g_img in imgList:
        img_tag = g_img.find("img")  # img 태그를 찾음
        if img_tag:
            img_url = img_tag.get("src")
            # URL이 상대 경로일 수 있으므로 절대 경로로 변환
            img_url = urljoin(driver.current_url, img_url)
            params_g.append(img_url)
    
    # 10. 이미지들을 로컬 디렉토리에 저장
    successful_downloads = 0
    for idx, p in enumerate(params_g, 1):
        if p:
            try:
                # URL에서 이미지 다운로드 시 Content-Type을 확인
                response = requests.get(p, stream=True)
                content_type = response.headers.get("Content-Type")
                
                # Content-Type을 확인하여 확장자 결정
                if content_type == 'image/jpeg':
                    ext = '.jpg'
                elif content_type == 'image/png':
                    ext = '.png'
                elif content_type == 'image/gif':
                    ext = '.gif'
                else:
                    ext = '.jpg'  # 기본적으로 .jpg 확장자 할당
                
                # 파일 이름 지정 (확장자 포함)
                file_path = f"c:\\data_image6\\{idx}{ext}"
                
                # 이미지 저장
                with open(file_path, 'wb') as out_file:
                    out_file.write(response.content)
                
                print(f"이미지 {idx} 저장 완료: {p}")
                successful_downloads += 1
                
            except Exception as e:
                print(f"이미지 {idx} 저장 실패: {e}")
        else:
            print(f"이미지 {idx}는 다운로드할 수 없습니다.")
    
    # 결과 출력
    total_images = len(params_g)
    print(f"{total_images} 장 중의 사진 중 {successful_downloads} 장의 사진이 성공적으로 저장되었습니다.")
    
    driver.quit()

 

 

# 함수 호출 예시
download_daum_image('고양이')