0. Intro
프로젝트 백업용 기록이다. KPOP의 광팬으로서 늘 음악 분석을 해보고 싶어했고, 노래 가사 분석 사이드 프로젝트를 진행하였다. (코드 복습 겸 .. 공부겸.. 개인 사심으로 세븐틴 컴백 기념.. )
처음은 당연히 데이터 수집부터 ! 웹 페이지상의 데이터를 수집하기 위해서는 크롤링을 활용할 수 있다. 그 중, beautifulsoup만으로는 크롤링할 수 없는 경우가 대다수이다!
- 스크래핑 과정 중 웹 상에서의 동작이 필요할 때: 로그인이 필요한 경우 등등
- 페이지를 이리저리 돌아다녀도 주소가 변하지 않는 경우: 웹페이지가 iframe형식일때 ex) 네이버 카페
따라서 이번 포스팅에서는 beautifulsoup과 selenium을 통해 멜론 홈페이지 에서곡명, 가사, 기타 정보 수집하는 과정을 다루려고 한다.
(나는 세븐틴 팬이므로 세븐틴 노래 정보를 수집하였다 ^_^ (요즘 한국어 없는 노래를 내는 그룹이 많아서 슬프다)
*깃헙 코드는 실행 시 가수를 입력받아 해당 가수의 가사를 수집하도록 만들어 놓았다.)
https://github.com/HwangJae-won/Music_Data/tree/main
1. 필요한 모듈 설치
## Melon Music crawling
import math
import time
import datetime
start = time.time()
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import time
## for processing
from konlpy.tag import Hannanum
import re
import pandas as pd
import numpy as np
import csv
import sys
## visualization
import matplotlib.pyplot as plt
import seaborn as sns
from collections import Counter
from wordcloud import WordCloud
from PIL import Image
## interactiveshell
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
#ignore warnings
import warnings
warnings.filterwarnings(action="ignore")
2. 크롤링 함수
여기서 뒤집어지는 점... 나때는 말야 ..... (약 2년,, 전) 크롬드라이버를 크롬 버전에 맞게 다운 받고, 경로를 맞게 저장해준 후 크롬드라이버를 불러와주어야 했다.
#chrome driver
driver = webdriver.Chrome('/Users/chromedriver')
driver.get(url)
그런데 최신 버전 셀레니움은 크롬드라이버 경로 지정 없이 그냥 바로 호출이 된다 ,,,,,,,!
driver = webdriver.Chrome()
driver.get(url)
크롬이랑 크롬드라이버 버전을 맞추는 귀찮은 과정을 이제는 하지 않아도 되는 것..
다들 pip install selenium --upgrade 혹은 pip uninstall selenium -> pip install selenium 을 통해 꼭꼭 업데이트하고 사용하셨으면 좋겠다.
업데이트되면서 사용하는 함수도 조금씩 바뀌었으니 셀레니움 공식 문서를 참고하면 좋을 것 같다.
url = "https://www.melon.com/"
print("가수 이름을 입력하세요")
singer = str(input())
#수집할 정보 리스트
titles =[]
infos =[]
lyricses=[]
def melon_crawling(url, singer):
##크롬 드라이버 호출
driver = webdriver.Chrome()
driver.get(url)
##페이지 이동
#검색창
driver.find_element(By.XPATH,'//*[@id="top_search"]').click()
#가수명 입력
driver.find_element(By.XPATH,'//*[@id="top_search"]').send_keys(singer)
#검색창 클릭
driver.find_element(By.XPATH,'//*[@id="gnb"]/fieldset/button[2]').click()
#곡 선택
driver.find_element(By.XPATH,'//*[@id="divCollection"]/ul/li[3]/a').click()
#아티스트명에서
driver.find_element(By.XPATH,'//*[@id="conts"]/div[3]/div[1]/a[2]').click()
driver.execute_script("window.scrollTo(0, 500)")
time.sleep(3)
# 곡정보 크롤링
try:
for page in range(1,6):
for i in range(1, 51): #50개씩 있음
#곡정보 칸으로 이동
sing_css= f'#frm_defaultList > div > table > tbody > tr:nth-child({i}) > td:nth-child(3) > div > div > a.btn.btn_icon_detail'
driver.find_element(By.CSS_SELECTOR,sing_css).click()
driver.execute_script("window.scrollTo(0, 500)")
time.sleep(3)
##페이지 파싱 및 정보 수집
html_source = driver.page_source
soup = BeautifulSoup(html_source, 'lxml')
try:
title =driver.find_element(By.CSS_SELECTOR, "#downloadfrm > div > div > div.entry > div.info > div.song_name").text
titles.append(title)
#세부 정보
info = driver.find_element(By.CSS_SELECTOR, "#downloadfrm > div > div > div.entry > div.meta").text
infos.append(info)
#가사
lyrics =driver.find_element(By.CSS_SELECTOR, "#d_video_summary").text
lyricses.append(lyrics)
print(f'{i}번째 곡 크롤링 완료, 곡 제목:', title)
except:
print("가사 정보가 없습니다.")
lyricses.append("unknown")
print(f'{i}번째 곡 크롤링 완료, 곡 제목:', title, "* 특이사항: 가사 없음")
driver.back()
print(f"{page}번째 페이지 크롤링 완료")
print("====================")
n= page+1
print(f'{n}번째 페이지 크롤링 시작 ')
last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
driver.find_element(By.XPATH, f'//*[@id="pageObjNavgation"]/div/span/a[{page}]').click()
time.sleep(3)
except:
print("더 이상 수집할 수 있는 정보가 없습니다. ")
pass
driver.close()
return titles, lyricses, infos
titles, lyricses, infos = melon_crawling(url, singer)
코드 짜면서 처리해야했던 점
- 가사가 없는 경우가 있어 예외처리를 해주어야했음
- 각 페이지는 50개씩 곡이 있었지만 마지막 페이지의 경우 개수가 맞지 않으므로 예외처리
- 페이지 파싱 과정을 반복문 안에 넣어주지 않아 중복 수집되었다. 해당 부분 주의할 것
3. 전처리하여 최종 결과물 저장
import pickle
print(len(titles), len(lyricses), len(infos))
with open("titles.pkl", 'wb') as f:
pickle.dump(titles, f)
with open("lyricses.pkl", 'wb') as f:
pickle.dump(lyricses, f)
with open("infos.pkl", 'wb') as f:
pickle.dump(infos, f)
print("저장 완료")
#전처리
df= pd.DataFrame({"title": titles,
"lyrics":lyricses,
"information":infos})
album = []
date= []
genre =[]
for i in range(len(df)):
album.append(df.information[i].split('\n')[1])
date.append(df.information[i].split('\n')[3])
genre.append(df.information[i].split('\n')[5])
df['album'] = album
df['date'] = date
df['genre'] = genre
df.drop(["information"], axis =1, inplace=True )
df.to_csv("Melon_Crawling.csv", index=False)
end = time.time()
sec = (end - start)
result = datetime.timedelta(seconds=sec)
result_list = str(datetime.timedelta(seconds=sec)).split(".")
print("총 수행시간 :", result_list[0])
- 각 정보는 pickle 파일로 저장, 데이터 프레임으로 최종 데이터 반환, 수행시간 보여주기
4. py 파일로 정리, 실행 화면
추후 진행할, 해보고싶은 사항
- 전처리 코드 정리: 일본, 중국곡, 피쳐링 곡 제외, 영어 노래 분리
- 앨범별로 데이터정리, 장르별
- 한국 가사 추출: 시각화 (앨범별)
- NLP 기초 모델: LDA, 감성 분석 , CBOW, LSTM=> 앨범이 주는 컨샙 분석
- 감성 분석 + 추천시스템
-Lyrics-Based Music Genre Classification Using a Hierarchical Attention Network 논문 구현
https://github.com/alexTsaptsinos/lyricsHAN
NLP 복습하면서 천천히 굴러갑니다~
'공모전 및 프로젝트' 카테고리의 다른 글
[코딩하는 캐럿] 세븐틴 태블로 대시보드 만들기 (1) - 나무위키 정보 크롤링 (0) | 2023.05.10 |
---|