본문 바로가기

복습용 기술공부

빌보드 크롤링 _ 레이블 수정 과정

@ 나중에 보면서 복기하려고 적는 글

@ 옆 친구가 빌보드 100위 가져오면, 내가 다른 사이트에서 추가 정보 얻어오는 코드

@ 하루 뒤에 정리하면서 보니, 그냥 spotify api 쓸 걸 그랬다.

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup as bs
import requests
import time
import os
import urllib.request
import re
import pickle

크롤링 chrome 열기

wd = webdriver.Chrome()
path1 = 'https://tunebat.com/'
wd.get(path1)

검색 조건 함수

def searchSong(song_name, song_artist):
    # 검색 조건
    return  song_artist + ' ' + song_name

검색 후 데이터 가져오는 함수,

전처리를 어떻게 처리할까? 검색 후 전처리 할까?

자료 없는 구문은 어떻게 처리해야할까?

예외 처리 _ 지금 정리하면서 적으니까 exception 오류 별로 나눠서 해야하는데 빼먹었다.

전처리도 조금 더 고민해야할 듯

def className(song_name,song_artist):
    # 타이틀, 가수명 재정리
    try :
        artist = wd.find_elements(By.CSS_SELECTOR, '.ant-typography-single-line')
        title = wd.find_elements(By.CSS_SELECTOR, '.ant-typography-ellipsis-multiple-line')
        
        if not song_artist :
            if not song_name :
                return 'name_is_not_define', 'artist_is_not_define', 0, 0, 0
            return song_name, 'artist_is_not_define', 0, 0, 0
        elif not song_name :
            return 'name_is_not_define', song_artist, 0, 0, 0
        
        # notion[0] 메이저,마이너, [1] bpm, [2] camelot scale : 필요 없음, [3] : popularity
        notion = wd.find_elements(By.CSS_SELECTOR, '.lAjUd')

        # 음역 key 삭제
        key = notion[0].text.split(' ')[1]

        return title[0].text, artist[0].text, key, notion[1].text, notion[3].text
    
    except Exception as e:
        print(f'{e} : // {song_artist} 의 {song_name} 는 없거나, 자료 없음')
        return song_name, song_artist, 0, 0, 0
        

    # 전처리해서 불러오지 말고 불러온 후에 전처리 시키는게 오류 안 집힐 듯,
    
    # i = 0
    # while i <= 10:
    #     re_artist = artist[i].text.lower().replace(' ','')
    #     re_title = title[i].text.lower().replace(' ','')
    #     re_song_artist = song_artist.lower().replace(' ','')
    #     re_song_name = song_name.lower().replace(' ','')
    #     # print(re_artist,re_title,re_song_artist,re_song_name)
    #     if (re_artist == re_song_artist) and (re_title == re_song_name):
    #         key = notion[4*i].text.split(' ')[1]
    #         # print(title[i].text, artist[i].text, key, notion[4*i+1].text, notion[4*i+3].text)
    #         return title[i].text, artist[i].text, key, notion[4*i+1].text, notion[4*i+3].text
    #     i += 1

딕셔너리 생성부분

def newDict(classname, rank):
    # 사전 정의
    new_dict = {}
    if classname :
        new_dict = {
            'title' : classname[0], 
            'artist' : classname[1],
            'rank' : rank,
            'harmony' : classname[2],
            'bpm' : classname[3],
            'populality' : classname[4]
        }
        return new_dict

크롤링 검색창에 검색 후 버튼을 눌러주는 코드, 이후 검색창 내용은 지워준다.

global wd는 지워도 작동할 듯, 어떤 오류 해결하려고 쓴 코드인데 그냥 놔둠

여기도 예외처리 한번에 묶어서 해버림, 나중에 나눠야지 (지금은 시간없으니 그냥 가고)

el.clear()로 다 지워진다고 하는데, 나는 안 됐음.

공식문서 뒤져서 BACKSPACE 사용하고, 하나씩 일일히 지우다가 더 빠른방법 생각하다가

CONTROL +'a'로 한번에 선택된다는 것을 알아냄.

strip_emoji는 인터넷에서 찾아서 약간 수정해서 만듬 (이모지 제거 _ 틱톡 인기곡에 왜 이렇게 이모지 쓴 파일이 많은지..., 이모지 처리를 해도 안지워지는 것이 많아서 그냥 except으로 밀어버림)

def searchBar(song_name,song_artist,rank):
    global wd
    try:
        # 크롤링 선택자
        el = wd.find_element(By.CSS_SELECTOR, '.J4uKH .ant-input-lg.ant-input')
        search_song = searchSong(song_name,song_artist)

        song_artist = strip_emoji(song_artist)
        song_name = strip_emoji(song_name)

        el.send_keys(search_song)
        btn = wd.find_element(By.CSS_SELECTOR, '.ant-btn.ant-btn-submit.mWyPe')
        btn.click()

        time.sleep(3)
        print(song_name,song_artist)
        # el.clear()
        el.send_keys(Keys.CONTROL + 'a')
        el.send_keys(Keys.BACKSPACE)
        classname = className(song_name,song_artist)
        new_dict = newDict(classname, rank)
        # print(new_dict)
        return new_dict
    except Exception as e:
        print(f'{e} : // {song_artist} 와 {song_name}에 이모지가 들어가 있음')
        new_dict = {
            'title' : 'name_is_not_define', 
            'artist' : 'artist_is_not_define' ,
            'rank' : rank,
            'harmony' : 0,
            'bpm' : 0,
            'populality' : 0
        }
        return new_dict

크롤링 작업 단계

def doLastDict(weektime, billboard):
    # billboard['weeks']['index'] -> 'title', 'artist', 'rank'
    for j in range(weektime):
        print('----------')
        # print(newlist)
        newlist = []
        
        for i in range(100):
            title = billboard[j][i]['title']
            artist = billboard[j][i]['artist']
            rank = billboard[j][i]['rank']
            # print(title,artist,rank)
            new_dict = searchBar(title,artist,rank)
            # print(new_dict)
            newlist.append(new_dict)
            last_dict[j] = newlist
            print('---', j, i+1, '진행중')
        print(f'{j} --- 진행완료')
    return last_dict

실행 코드

# 실행코드
last_dict = {}

# 조사 주 입력
weektime = int(input())
weektime += 1

# 크롤링 시작
wd = webdriver.Chrome()
path1 = 'https://tunebat.com/'
wd.get(path1)

time.sleep(5)

# billboard 크롤링 파일 불러오기
with open('project3_billboard/billboard_JSON.pickle', 'rb') as f:
    billboard = pickle.load(f)

# 크롤링
do_last_dict = doLastDict(weektime, billboard)    

# 크롤링 파일 저장
with open(f'project3_billboard/billboard_JSON_add_{weektime}weeks.pickle', 'wb') as f:
    pickle.dump(do_last_dict, f, pickle.HIGHEST_PROTOCOL)