오늘은 국내 대중가요 가사 텍스트 데이터를 이용하여 감정 분석을 진행할 목적으로
노래 정보를 파이썬으로 추출하였습니다.
구글 Colaboratory에서 동작하는 관련 소스코드를 공유합니다.
1. 추출하려는 노래 목록
- 멜론 > 멜론차트 > 시대 > 2023년도 1위 ~ 100위
- 해당 URL : https://www.melon.com/chart/age/index.htm?chartType=YE&chartGenre=KPOP&chartDate=2023&moved=Y&idx=1
2. 파이썬 소스코드
import re import requests from bs4 import BeautifulSoup import pandas as pd from time import sleep import os from tqdm import tqdm # 2023년대 노래 시대별차트 headers = { 'User-Agent': ('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' '(KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36') } age_url = "https://www.melon.com/chart/age/list.htm" params = { 'idx': '1', 'chartType': 'YE', # 10년 단위로 검색하는 부분과 연관 'chartGenre': 'KPOP', # 가요검색: KPOP, 팝송검색: POP 'chartDate': '2023', # 검색연도 'moved': 'Y', } response = requests.get(age_url, params=params, headers=headers) soup = BeautifulSoup(response.text, 'html.parser') song_list = soup.select('.lst50, .lst100') # 데이터프레임 초기화 columns = ['chartDate', 'rank', 'title', 'singer', 'album_name', 'release_date', 'genre', 'lyric', 'composer', 'lyricist', 'arranger'] song_data = pd.DataFrame(columns=columns) # tqdm 라이브러리로 진행 상황 바 표시 for i, meta in tqdm(enumerate(song_list, 1), total=len(song_list), desc="Processing songs"): rank = i try: title = meta.select('a[href*=playSong]')[0].text except: title = meta.select('.wrap_song_info .ellipsis')[0].text title = title.strip() song_id_html = str(meta.select('a[onclick*=SongDetail]')) matched = re.search(r"\'(\d+)\'", song_id_html) song_id = matched.group(1) song_url = 'https://www.melon.com/song/detail.htm?songId=' + song_id response = requests.get(song_url, params=params, headers=headers) soup = BeautifulSoup(response.text, 'html.parser') # 가수 singer_html = soup.select('.wrap_info .artist a') singer_s = ', '.join([html['title'] for html in singer_html if html['title']]) if singer_html else 'Various Artists' # 앨범명 album_name = soup.select('.list dd')[0].get_text(strip=True) # 발매날짜 release_date = soup.select('.list dd')[1].get_text(strip=True) # 장르 genre = soup.select('.list dd')[2].get_text(strip=True) # 가사 lyric = '없음' lyric_html = soup.select_one('.section_lyric .wrap_lyric .lyric') if lyric_html: lyric = lyric_html.get_text(strip=True, separator='\n') # 작사, 작곡, 편곡 member_roles = {'작사': 'lyricist', '작곡': 'composer', '편곡': 'arranger'} members = {v: '' for k, v in member_roles.items()} for entry in soup.select('.section_prdcr .list_person .entry'): role = entry.select_one('.meta').get_text(strip=True) if role in member_roles: members[member_roles[role]] = entry.select_one('.artist').get_text(strip=True) # 데이터프레임에 추가 row = pd.Series([params['chartDate'], rank, title, singer_s, album_name, release_date, genre, lyric, members['composer'], members['lyricist'], members['arranger']], index=song_data.columns) song_data = pd.concat([song_data, pd.DataFrame([row])], ignore_index=True) sleep(1) # IP 차단 방지용
댓글