Python Selenium을 활용한 영화 리뷰 스크래핑 및 시각화

2024. 4. 6. 17:09·[프로그래머스] 데이터 엔지니어링 데브코스 3기/기타

서론

데브코스 : 데이터 엔지니어링을 수강하면서 동적 웹 스크래핑을 진행하기 위한 Selenium 라이브러리를 배웠다. 강의에서 배운 내용을 다시 한번 활용해 보며, 익숙해지기 위해 해당 프로젝트(?)를 진행하였다. 단지 몇 시간 동안 들은 강의이고, 웹 관련 배경 지식이 없기 때문에 올바른 코드인지 확신할 수는 없지만, 강의 내용을 복습하는 것에 의의를 두려고 한다. 그래서 진행할 프로젝트는 무난하게 진행할 수 있는 영화 사이트의 리뷰를 스크래핑 및 시각화이다. 작성한 코드를 설명하고, 왜 해당 코드를 작성하였는지 설명하는 방식으로 진행할 것이다.

  • 개발 환경 : Colab - Python
  • 라이브러리 : Selenium, wordcloud, matplotlib, seaborn, collections, konlpy, time

진행 과정

진행 과정을 크게 분류하여 나열하면 다음과 같다.

  1. 라이브러리, 폰트 설치, 경로 설정, 한글 깨짐 방지
  2. 라이브러리 불러오기
  3. Selenium Driver 초기화
  4. 영화 제목 추출, 영화 선정 및 검색
  5. 해당 영화의 리뷰 명사 추출
  6. 시각화

영화 리뷰 사이트 스크래핑 및 시각화

https://www.cgv.co.kr/ << 프로젝트가 진행되는 웹 사이트

 

영화 그 이상의 감동. CGV

12 --> 11 --> D Day

www.cgv.co.kr

리뷰를 스크래핑하기 위해 활용한 사이트는 CGV이다. 웹 사이트의 검색 창을 활용하여 '명탐정 코난'의 리뷰를 스크래핑 및 명사 추출과 wordcloud와 seaborn을 활용해 시각화를 진행해 볼 것이다. 명탐정 코난을 고른 이유는 필자가 좋아하기 때문이다!

라이브러리, 폰트 설치, 경로 설정, 한글 깨짐 방지

pip, apt-get 등 터미널 환경에서 진행되는 코드를 가장 먼저 처리해 주었다.

# 사용할 라이브러리 설치
!pip install selenium
!pip install konlpy

# colab 환경에서 진행하기 위한 selenium 경로 설정
!apt-get update
!apt install chromium-chromedriver
!cp /usr/lib/chromium-browser/chromedriver /usr/bin

# wordcloud을 위한 폰트 설치
!apt-get install fonts-nanum*
!apt-get install fontconfig

# 한글 깨짐 방지
!sudo apt-get install -y fonts-nanum
!sudo fc-cache -fv
!rm ~/.cache/matplotlib -rf

라이브러리 불러오기

서론에서 언급했던 프로젝트를 진행하기 위해 필요한 라이브러리를 불러온다.

# Selenium 라이브러리
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver import Keys, ActionChains
import time

# 시각화 라이브러리
import matplotlib.pyplot as plt
import seaborn as sns
from wordcloud import WordCloud

# 단어의 개수를 세기 위한 라이브러리
from collections import Counter

# 명사 추출을 위한 라이브러리
from konlpy.tag import Hannanum

Selenium Driver 초기화

로컬 환경에서의 초기화

만약 Colab 환경이 아닌 로컬 환경이라면, 추가적인 import를 진행하여 아래와 같은 코드를 통해 driver를 활용할 수 있을 것이다. 이렇게 진행하면 웹 페이지가 실제로 열리고, 시각적으로 확인하며 실습을 진행할 수 있다.

driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))

Colab에서의 초기화

Colab 환경에서는 웹 페이지를 띄울 수 없기 때문에 option을 추가하여 진행해야 한다. 아래의 코드는 웹 페이지를 띄우지 않게 하는 옵션을 추가하고 driver를 초기화한 것이다.

options = webdriver.ChromeOptions()
options.add_argument('--headless')        # Head-less 설정
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')

driver = webdriver.Chrome(options=options)

영화 제목(명탐정 코난) 추출

이제 driver를 활용하여 영화 제목을 가져올 차례이다. CGV 홈페이지에서 '명탐정 코난'을 검색했을 때, 총 24개의 영화가 나타나고 목록은 다음과 같다.

'명탐정 코난' 검색

영화 제목 추출

 한 페이지에 6개의 영화가 있어 총 4페이지의 목록의 영화 제목을 추출해야 한다. 해당 페이지는 페이지네이션이 적용되어 url 마지막에 '~?query=명탐정코난&page=1'과 같은 형태로 page를 구분한다. 따라서 숫자만 변경하여 get 요청 후 제목을 추출한다. 영화 제목을 추출하는 방법은 영화 목록을 감싸고 있는 'ul' 태그의 클래스 이름인 'searchingMovieResult_list'를 활용한다. 또한 웹 페이지를 조작하는 중에는 사용자에게 입력을 받는 input()을 실행이 불가능해 driver를 닫아주었다.(영화를 선정할 때, input()을 활용할 것이다.)

페이지네이션

movie_name = []

# 영화 이름 추출
for i in range(1, 5):
    driver.get("http://www.cgv.co.kr/search/default.aspx?query=%EB%AA%85%ED%83%90%EC%A0%95%EC%BD%94%EB%82%9C&page={}".format(i))
    movie_name += driver.find_element(By.CLASS_NAME, "searchingMovieResult_list").text.split('\n')
    time.sleep(0.5)

# 페이지 닫기
driver.close()

영화 제목 전처리

위의 코드를 실행하면, 영화 제목뿐만 아니라 사진에 보이는 것처럼 '2023.07.20 개봉'과 같은 문자열이 섞여있다. 그래서 '명탐정'이 포함된 문자열만 추출하여 재저장하고, 사용자가 영화를 더 쉽게 선택할 수 있도록 딕셔너리에 저장하였다.

movie_name = [m for m in movie_name if "명탐정" in m]

movie_dict = dict(zip(range(1, len(movie_name)+1), movie_name))

movie_dict
# result
# {1: '명탐정코난-흑철의 어영',
#  2: '명탐정코난-하이바라 아이 이야기 ~흑철의 미스터리 트레인',
#  3: '명탐정 코난-할로윈의 신부',
# ...
#  23: '명탐정 코난 : 천공의 난파선',
#  24: '명탐정 코난 극장판 13 - 칠흑의 추적자'}

영화 선정 및 검색

영화 선정

try-except 구문을 활용해서 사용자가 올바른 입력을 할 때까지 입력을 진행하도록 하였다.

for k, v in movie_dict.items():
    print(k, v)

while True:
    try:
        movie = movie_dict[int(input("영화를 선택해주세요. (1 ~ 24)\n"))]
        break
    except:
        print("올바른 번호를 입력해주세요")

print("선택한 영화 :", movie)

영화 검색 및 페이지 접속

선정한 영화의 리뷰를 찾기 위해 다시 driver를 실행하고, get을 요청한다. 그리고 검색을 위한 'input' 태그를 가진 요소의 ID인 'header_keyword'에 선정한 영화 제목을 입력하고, 검색 버튼의 ID를 활용하여 클릭하도록 하였다. 검색 후 해당 영화의 상세 정보를 확인하기 위해 클릭하는 작업도 추가해 주었다.

영화 검색 및 페이지 접속

driver = webdriver.Chrome(options=options)

driver.get("http://www.cgv.co.kr/")

# 영화 검색
text_input = driver.find_element(By.ID, "header_keyword")
ActionChains(driver).send_keys_to_element(text_input, movie).perform()
time.sleep(0.5)

search_button = driver.find_element(By.ID, "btn_header_search")
ActionChains(driver).click(search_button).perform()
time.sleep(0.5)


# 페이지 접속
link_button = driver.find_element(By.CLASS_NAME, "searchingMovieResult_list").find_element(By.TAG_NAME, 'img')
ActionChains(driver).click(link_button).perform()

p. 1-10 리뷰 명사 추출

추천순 리뷰로 변경

신뢰성 있는 정보를 얻기 위해 추천순으로 변경 후 리뷰를 추출하도록 한다. '최신순'과 '추천순'을 담고 있는 'ul' 태그의 ID인 'sortTab'과 내부 태그인 'a'를 활용하면, 두 개의 객체가 나오게 된다. '최신순' 링크와 '추천순' 링크이다. 순서대로 리스트에 담기므로 리스트 1번에 '추천순'이 담기게 되며, 이를 클릭하도록 코드를 작성하였다.

추천순 리뷰

rec_button = driver.find_element(By.ID, "sortTab").find_elements(By.TAG_NAME, "a")[1]
ActionChains(driver).click(rec_button).perform()

p. 1-10 리뷰 추출

리뷰 페이지를 넘어갈 때도 페이지네이션을 통해 진행하려고 했지만, 원하는 대로 수행되지 않았다. 페이지에 따라 url이 '~#1'과 같이 # 뒤에 페이지 번호가 나타났다. 하지만 # 뒤의 번호를 바꾸더라도 페이지가 변하지 않아 해당 방법을 적용하지 못했다. 따라서 find_elements가 요소를 저장할 때, 위에서 아래로 저장하는 것을 이용해서 반복문으로 각 페이지의 리뷰를 추출할 수 있도록 하였다.

reviews = []

for i in range(10):
    page_button = driver.find_element(By.ID, "paging_point").find_elements(By.TAG_NAME, "a")[i]
    ActionChains(driver).click(page_button).perform()
    time.sleep(0.5)

    comments = driver.find_elements(By.CLASS_NAME, "box-comment")
    for c in comments:
        reviews += c.text.split('\n')
        
reviews[:10]
# result
# ['스릴넘치고 전에 개봉한 영화보다 더 재밌었어요! 다음편이 기대되요.',
#  '코난은 왜 나이를 먹지 않을까. 짱구와 같은 약을 먹은거 같은데 부럽',
#  '그냥 다 최고에요 ㅠㅠㅠㅠ 명탐정코난 전혀 보지도 않고 등장인물에 코난만 아는 제 친구랑 오늘 씨지브이가서 오늘 한국에 개봉한 코난 영화 그 친구도 저처럼 되게 재미있었다네요 !!',
#  '코난을 좋아하는 아이들은 재밌게볼거같아요~ 어른들은 약간 지루하실수 있겠네요~^^',
#  '코난 이즈 뭔들ㅋㅋ최고예요!',
#  '명탐정코난 다른편들보다는 감동이 덜했지만 재미있었어요!!',
#  '역대코난중 최고!!!!!!+!!!!',
#  '저번에 나왔던거라 이미 스토리는 다알았는데 더빙으로 다시한번보니까 재미있어요!!',
#  '좋았어요 카드도 주고ㅎ2장다 주시지 하나 고르라고하니..한번더봐야하나 고민입니다',
#  '역시 코난!! 아쉬운건 더빙인것 그래도 언제나 듣던 더빙목소리라 어색하진 않아ㅋㅋ']

리뷰 명사 추출 및 단어 개수 세기

konlpy의 Hannanum을 사용해서 명사 추출을 진행하였다. 원래 한글 형태소 추출이 쉽지 않은 것을 알고 있었지만, 생각보다 제대로 추출이 안 되는 것을 느꼈다. 그래도 여기서는 웹 스크래핑을 배우는 목적이 있으므로 길이가 긴 것을 제외해 준 것 말고는 추가적인 처리 작업을 수행하지 않았다.

hannanum = Hannanum()
words = []
for r in reviews:
    nouns = hannanum.nouns(r)
    words += [noun for noun in nouns if len(noun) > 1]

words = [word for word in words if len(word) < 10]

counter = Counter(words)

시각화

시각화는 '명탐정 코난-진홍의 수학여행'으로 진행하였다.

상위 10개 단어 시각화

명사 추출이 제대로 되지 않아 ',ㅡ'가 상위 목록에 들어있는 것을 볼 수 있다.

x = [v[0] for v in counter.most_common(10)]
y = [v[1] for v in counter.most_common(10)]

plt.title("상위 10개 단어 목록")
plt.xlabel("단어")
plt.ylabel("빈도")
plt.ylim(0, y[0] + 2)
sns.barplot(x=x, y=y)

상위 10개 단어 목록

워드클라우드 시각화

wordcloud = WordCloud(
    font_path='/usr/share/fonts/truetype/nanum/NanumGothic.ttf',
    background_color='white',
    width=1000,
    height=1000
)
plt.axis('off')
img = wordcloud.generate_from_frequencies(counter)
plt.imshow(img)

워드클라우드

결론

배운 내용만을 활용하였기 때문에 어려운 작업이 포함된 것도 아니고 시간이 많이 걸리는 작업도 없었다. 간단하게 배운 내용을 활용해 볼 수 있는 시간이었고, 이전부터 생각만 해봤던 작업이었는데 실제로 해보니 재밌었던 시간이었다. 지금처럼만 데브코스를 진행한다면, 여기에 다른 요소를 많이 추가하는 결과와 실력을 얻을 수 있을 거라 확신한다.

참고링크

구글 코랩으로 크롤링하기

https://modulabs.co.kr/blog/google_colab_crawling_tip/

 

python list to dict 리스트 딕셔너리로 변환하기

https://zel0rd.tistory.com/77

 

한국어 wordCloud 생성

https://velog.io/@dltpal07/%ED%95%9C%EA%B5%AD%EC%96%B4-wordCloud-%EC%83%9D%EC%84%B1

 

구글 코랩(colab) 한글 깨짐 현상 해결방법

https://teddylee777.github.io/colab/colab-korean/

'[프로그래머스] 데이터 엔지니어링 데브코스 3기 > 기타' 카테고리의 다른 글

[3기] 프로그래머스 데브코스 데이터 엔지니어링 수료 후기  (4) 2024.08.25
[시행착오] 데브코스 3차 프로젝트(Airflow 활용 ETL)  (0) 2024.06.20
데이터 엔지니어링 OT 및 특강  (4) 2024.03.22
[3기] K-Digital Training: 데이터 엔지니어링 데브코스 지원 후기  (0) 2024.03.11
'[프로그래머스] 데이터 엔지니어링 데브코스 3기/기타' 카테고리의 다른 글
  • [3기] 프로그래머스 데브코스 데이터 엔지니어링 수료 후기
  • [시행착오] 데브코스 3차 프로젝트(Airflow 활용 ETL)
  • 데이터 엔지니어링 OT 및 특강
  • [3기] K-Digital Training: 데이터 엔지니어링 데브코스 지원 후기
기억에 남는 블로그 닉네임
기억에 남는 블로그 닉네임
  • 기억에 남는 블로그 닉네임
    얕게, 깊게
    기억에 남는 블로그 닉네임
  • 전체
    오늘
    어제
  • 블로그 메뉴

    • 홈
    • 방명록
    • 글쓰기
    • 분류 전체보기
      • Data Engineering
        • Airflow
        • 빅데이터
        • 자동화
        • 기타
      • Infra
        • AWS
        • Terraform
        • [인프라 구축기] Terraform 활용 AWS ..
      • CS
        • 자료구조
        • 알고리즘
        • 네트워크
        • 데이터베이스
        • 이것이 취업을 위한 코딩 테스트다 with 파이썬
      • Python
      • Web
      • Git
      • 기타
        • 취업 & 진로
        • 회고록
        • 기타
      • 프로젝트 단위 공부
        • [부스트코스] DataLit : 데이터 다루기
        • [개인 프로젝트] 공모전 크롤링
        • [개인 프로젝트] FC Online 공식 경기 분..
        • 프로젝트 개선 방안
      • [프로그래머스] 데이터 엔지니어링 데브코스 3기
        • TIL(Today I Learn)
        • 숙제
        • 기타
      • 알고리즘 연습
        • 프로그래머스
        • 백준
  • 링크

    • 깃허브
    • 링크드인
  • 인기 글

  • 최근 글

  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
기억에 남는 블로그 닉네임
Python Selenium을 활용한 영화 리뷰 스크래핑 및 시각화
상단으로

티스토리툴바