Melon Playlist 추가 자동화
Selenium
을 이용해 Melon
에서 음악을 검색해 Playlist에 추가하는 과정을 자동화한다.
Bugs
에서 Melon
으로 갈아탔는데 그동안 Bugs에서 듣던 노래가 500곡이 넘어서.. 일일이 검색해 추가하기가 번거로워 Python Selenium으로 playlist 검색해 추가하는 자동화 스크립트를 만들어봄.
Selenium은 세션을 이용해 크롤링을 할 수 있는 정도로만 알고있었는데, 패키지 내 WebDriver로서 활용할 수 있는 클래스가 많다. 로그인 하는 과정과 음악을 담는 과정에서 별도의 Window가 사용되는데 드라이버의 switch_to
메소드를 이용해서 여러 창들을 핸들링할 수 있고, implicitly_wait
뿐만 아니라 WebDriverWait
을 이용해서 필요한 정보가 나올 때까지 적절하게 세션을 대기시킬 수 있다. Alert
를 이용해 웹 브라우저의 Alert 팝업도 처리 가능.
음악 목록
아래와 같이 plist.txt
파일로 음악 목록을 준비.
담아둔 음악이 수천곡이 넘으면 이것도 자동화해야할 것 같은데 500곡 정도밖에 안돼서, 재생 목록을 벅스 앨범에 담고 그냥 마우스로 복사해 정제함.
괄호는 모두 제거하고 곡 명 - 아티스트 명
형태로 정리했는데 멜론에서 이 상태로 검색하니 결과가 잘 나온다.
Jenny - Mae Muller
Everything's Gonna Be Alright - PJ Morton [Maroon 5]
Other Side Of The World - Melissa Polinar
바람이 분다 - 이소라
Aqua Man - 빈지노
누군가의 위로가 필요한 밤 - 한올
HER - 블락비
너 없인 안 된다 - 비투비
Bellbottoms - Jon Spencer Blues Explosion
Gettin' Over You - David Guetta
1월부터 6월까지 - 윤종신
그대가 내 안에 박혔다 - 황치열
화 - 매드 클라운
발걸음 - 에메랄드 캐슬
Sunburn - Droeloe
Roar - Katy Perry
결혼 - 문문
Birthday - Katy Perry
Gucci - 제시
솔직하게 말해서 나 - 김나영
Woman - Kesha
가만히 눈을 감고 - 정재욱
고백 - 양다일
은영이에게 - KCM
사랑한다는 말 - 이승기
사랑...그 흔한 말 - 박효신
그 노래 - 김동률
...
소스 코드
- 사용하는 크롬 버전에 맞는 chromedriver 를 준비해야 함
- 아래
${EMAIL_ADDR}
,${PASSWORD}
위치에 계정명과 비밀번호를 대입하고 실행
import traceback
from selenium import webdriver
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.support.wait import WebDriverWait
from selenium.common.exceptions import NoSuchElementException, NoAlertPresentException
driver = webdriver.Chrome('./chromedriver.exe')
driver.implicitly_wait(2)
driver.get('https://www.melon.com/index.htm')
driver.find_element_by_xpath('//*[@id="gnbLoginDiv"]/div/button/span').click()
driver.find_element_by_xpath('//*[@id="conts_section"]/div/div/div[1]/button').click()
WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) == 2)
driver.switch_to.window(driver.window_handles[1])
driver.find_element_by_id('loginEmail').send_keys('${EMAIL_ADDR}')
driver.find_element_by_id('loginPw').send_keys('${PASSWORD}')
driver.find_element_by_xpath('//*[@id="login-form"]/fieldset/button').click()
WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) == 1)
driver.switch_to.window(driver.window_handles[0])
# 메인 검색 창과 검색 결과 화면의 검색창 element id 가 달라, 아래 루프에서는 검색 결과 화면이 검색창 element id로 통일시키기 위해 임의 검색을 한번 수행
driver.find_element_by_id('top_search').send_keys('oboki')
driver.find_element_by_xpath('//*[@id="gnb"]/fieldset/button[2]/span').click()
# Playlist 로드
file = open('plist.txt',mode='rt',encoding='utf-8')
plist = file.readlines()
file.close()
# Loop
for p in plist:
try:
WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) == 1)
driver.switch_to.window(driver.window_handles[0])
p = p.split('\n')[0]
driver.find_element_by_id('top_search').clear()
driver.find_element_by_id('top_search').send_keys(p)
driver.find_element_by_xpath('//*[@id="header_wrap"]/div[3]/fieldset/button[2]/span').click()
driver.find_element_by_xpath('//*[@id="divCollection"]/ul/li[3]/a').click()
driver.find_element_by_xpath('//*[@id="frm_defaultList"]/div/table/tbody/tr[1]/td[3]/div/div/button[2]/span').click()
WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) == 2)
driver.switch_to.window(driver.window_handles[1])
tmp = driver.window_handles[1]
driver.find_element_by_xpath('//*[@id="plylstList"]/div/table/tbody/tr/td[1]/div/div/span').click()
driver.find_element_by_xpath('//*[@id="plylstList"]/div/table/tbody/tr/td[1]/div/span/button/span/span').click()
try:
alert = Alert(driver)
alert_text = alert.text
alert.accept()
driver.close()
print(alert_text)
except NoAlertPresentException:
while True:
if len(driver.window_handles) > 1:
if (tmp != driver.window_handles[1]):
break
WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) == 2)
driver.switch_to.window(driver.window_handles[1])
driver.find_element_by_xpath('/html/body/div/div/div[2]/button/span/span').click()
except NoSuchElementException:
print("Error: "+p)
traceback.print_exc()
continue
except IndexError:
print("Error: "+p)
traceback.print_exc()
continue
driver.close()
Melon 사용 후기
기존에 듣던 곡은 Melon으로 전부 다 옮기긴 했는데 며칠 써보니 Bugs가 더 좋은 것 같다.
- 기기등록 가능한 수가 멜론은 한 개이고 벅스는 두 개
- 벅스는 저장하는 음원의 음질을 선택할 수 있고 저장하고자 하는 곡만 선택해서 저장 가능
- 멜론은
오프라인 재생
기능을 이용하면 자동적으로 캐시하는데 - 이때 음질이 가장 낮은 상태로 저장되고
- 해당 기기가 무조건 오프라인 상태이어야 스트리망을 하지 않고 캐시된 파일을 사용
- 멜론은
- 멜론은 스트리밍 플러스 요금제까지 FLAC 음원을 들을 수 없음
- 벅스는 기본 요금제에서도 FLAC 음원을 제한적으로 들을 수 있음
- Windows 환경에서 벅스 플레이어가 월등히 예쁘고 사용성이 좋음