Spotify API 음악데이터 저장을 위한 python 기본활용

2020-06-06

.

Data_Engineering_TIL(20200606)

[참고사항]

  • ‘Spotify API 음악데이터 저장을 위한 RDS 연결&기본활용’를 이어서 참고할 것

  • URL : https://minman2115.github.io/DE_TIL90/

[학습내용]

  • 먼저 Mysql RDS를 생성하고 아래와 같이 코드를 작성하고 RDS와 연결이 잘 되는지 테스트해본다.
import sys
import requests
import base64
import json
import logging
import pymysql

# 아래 세줄의 코드가 없으면 이 전체 코드의 실행결과 시
# UnicodeEncodeError: 'cp949' codec can't encode character '\u2013' in position 33:
# illegal multibyte sequence 애러발생하기 때문에 추가한 것임
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1) # 일반적으로 오류가 발생하면 exit 1을 주는 편이다.

    cursor.execute("SHOW TABLES")
    print(cursor.fetchall())

    print("connect success")
    sys.exit(0)

if __name__=='__main__':
    main()
  • 실행결과로 아래와 같은 결과를 확인할 수 있다.

((‘artist_genres’,), (‘artists’,))

connect success

  • 그리고 DBeaver에서 alter table pmstest.artist_genres drop column country 명령어로 country 컬럼을 날려준다.

  • 우리는 어떤식으로 데이터를 불러올건데 id, 장르, followers 이런게 정확히 어떤식으로 되어 있는지 모른다. 그래서 하드코딩으로 명시할 수가 없다.

일단은 insert 쿼리를 날린다면 다음과 같은 형식으로 날리게 될 것이다.

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1) # 일반적으로 오류가 발생하면 exit 1을 주는 편이다.

    query = "insert into pmstest.artist_genres (artist_id, genre) values ('3456','rock')"
    cursor.execute(query)
    conn.commit() ## commit을 해줘야지 레코드가 직접보이게 되고 이걸 안해주면 안보인다.

    sys.exit(0)
    
if __name__=='__main__':
    main()

위와 같이 코드를 작성하고 실행하면 3456, rock, 레코드 생성일자가 테이블에 insert되어진다.

그러면 아래와 같이 코딩을 해서 실행해보자

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1) # 일반적으로 오류가 발생하면 exit 1을 주는 편이다.

    query = "insert into pmstest.artist_genres (artist_id, genre) values ('%s','%s')" %('4567','pop')
    ## %s는 스트링을 말하는 것이고, %('4567','pop')으로 replace를 하겠다는 것이다.
    cursor.execute(query)
    conn.commit() ## commit을 해줘야지 레코드가 직접보이게 되고 이걸 안해주면 안보인다.

    sys.exit(0)
    
if __name__=='__main__':
    main()

그러면 ‘4567’,’pop’,’데이터 저장시간’ 레코드가 insert 되어진 것을 확인할 수 있을것이다.

위와 같이 %s를 이용해서 넣어주는 방법도 있지만 .format을 이용하는 것을 더 많이 쓰는 편이다. 코딩은 아래와 같다.

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1) # 일반적으로 오류가 발생하면 exit 1을 주는 편이다.

    query = "insert into pmstest.artist_genres (artist_id, genre) values ('{}','{}')".format('5668','hip-hop')
    
    ## [참고사항]
    ## {}안에 번호를 명시하여 .format()에 들어간 데이터의 순서를 지정할 수 있다.
    ## ex) "insert into pmstest.artist_genres (artist_id, genre) values ('{1}','{0}')".format('5668','hip-hop')
    ## 위와 같이 쿼리를 날리면 artist_id에 hip-hop이 들어가고 genre에 5678이 들어갈 것이다.
    ## 번호를 위와 같이 명시하지 않으면 그냥 순서대로 들어간다.
    
    cursor.execute(query)
    conn.commit() ## commit을 해줘야지 레코드가 직접보이게 되고 이걸 안해주면 안보인다.

    sys.exit(0)
    
if __name__=='__main__':
    main()

그러면 spotify API를 이용해서 아래와 같이 코딩하여 윤하를 검색해본다.

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    params ={
        "q" : "Younha",
        "type" : "artist",
        "limit" : "10"
    }

    r = requests.get("https://api.spotify.com/v1/search",params=params ,headers=headers)

    print(r.text['artists'])

    sys.exit(0)
    
if __name__=='__main__':
    main()

그러면 아래와 같이 애러가 날 것이다.

Traceback (most recent call last):
  File "pmstest.py", line 116, in <module>
    main()
  File "pmstest.py", line 44, in main
    print(r.text['artists'])
TypeError: string indices must be integers

파이썬을 이용해서 해당부분을 딕셔너리로 변환을 해줘야한다.

그럴때 필요한 패키지가 json 파이썬 패키지이다.

아래와 같이 코딩해서 다시 실행해본다.

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    params ={
        "q" : "Younha",
        "type" : "artist",
        "limit" : "3"
    }

    r = requests.get("https://api.spotify.com/v1/search",params=params ,headers=headers)
    raw =json.loads(r.text)
    print(raw['artists'])

    sys.exit(0)
    
if __name__=='__main__':
    main()

그러면 아래와 같이 검색이 잘 되는 것을 확인할 수 있다.

{'href': 'https://api.spotify.com/v1/search?query=Younha&type=artist&offset=0&limit=3', 'items': [{'external_urls': {'spotify': 'https://open.spotify.com/artist/6GwM5CHqhWXzG3l5kzRSAS'}, 'followers': {'href': None, 'total': 140615}, 'genres': ['k-indie', 'k-pop', 'korean pop'], 'href': 'https://api.spotify.com/v1/artists/6GwM5CHqhWXzG3l5kzRSAS', 'id': '6GwM5CHqhWXzG3l5kzRSAS', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab67616d0000b2734b89d54636763c641bce87e5', 'width': 640}, {'height': 300, 'url': 'https://i.scdn.co/image/ab67616d00001e024b89d54636763c641bce87e5', 'width': 300}, {'height': 64, 'url': 'https://i.scdn.co/image/ab67616d000048514b89d54636763c641bce87e5', 'width': 64}], 'name': 'Younha', 'popularity': 62, 'type': 'artist', 'uri': 'spotify:artist:6GwM5CHqhWXzG3l5kzRSAS'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/6Dh7PnzZRdWAaQF3juY2cq'}, 'followers': {'href': None, 'total': 40}, 'genres': [], 'href': 'https://api.spotify.com/v1/artists/6Dh7PnzZRdWAaQF3juY2cq', 'id': '6Dh7PnzZRdWAaQF3juY2cq', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/75132aececcaba20b93d6f39558a69652850e23b', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/5d7a9e6e31c59c0fc6a13845fad1901d44e13f17', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/1515538f08ae4a2607b1b0156655cdb9bf6489e5', 'width': 160}], 'name': 'Younhan', 'popularity': 0, 'type': 'artist', 'uri': 'spotify:artist:6Dh7PnzZRdWAaQF3juY2cq'}], 'limit': 3, 'next': 'https://api.spotify.com/v1/search?query=Younha&type=artist&offset=3&limit=3', 'offset': 0, 'previous': None, 'total': 4}

이번에는 artist에 key가 어떤게 있는지 확인해본다.

아래와 같이 코딩해서 실행해본다.

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    params ={
        "q" : "Younha",
        "type" : "artist",
        "limit" : "3"
    }

    r = requests.get("https://api.spotify.com/v1/search",params=params ,headers=headers)
    raw =json.loads(r.text)
    print(raw['artists'].keys())

    sys.exit(0)
    
if __name__=='__main__':
    main()

실행결과는 아래와 같다.

dict_keys(['href', 'items', 'limit', 'next', 'offset', 'previous', 'total'])

그러면 여기서 아래와 같이 코딩해서 item을 가져와보자

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    params ={
        "q" : "Younha",
        "type" : "artist",
        "limit" : "1"
    }

    r = requests.get("https://api.spotify.com/v1/search",params=params ,headers=headers)
    raw =json.loads(r.text)
    print(raw['artists']['items'])

    sys.exit(0)
    
if __name__=='__main__':
    main()

실행결과는 아래와 같다.

[{'external_urls': {'spotify': 'https://open.spotify.com/artist/6GwM5CHqhWXzG3l5kzRSAS'}, 'followers': {'href': None, 'total': 140615}, 'genres': ['k-indie', 'k-pop', 'korean pop'], 'href': 'https://api.spotify.com/v1/artists/6GwM5CHqhWXzG3l5kzRSAS', 'id': '6GwM5CHqhWXzG3l5kzRSAS', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab67616d0000b2734b89d54636763c641bce87e5', 'width': 640}, {'height': 300, 'url': 'https://i.scdn.co/image/ab67616d00001e024b89d54636763c641bce87e5', 'width': 300}, {'height': 64, 'url': 'https://i.scdn.co/image/ab67616d000048514b89d54636763c641bce87e5', 'width': 64}], 'name': 'Younha', 'popularity': 62, 'type': 'artist', 'uri': 'spotify:artist:6GwM5CHqhWXzG3l5kzRSAS'}]

우리는 그러면 아래 그림과 같은 구조의 RDS의 artist 테이블에 데이터를 insert를 해볼것이다.

image

그리고 아래와 같은 코드로 artist의 items의 키가 어떤것들이 있는지 확인해본다.

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    params ={
        "q" : "Younha",
        "type" : "artist",
        "limit" : "1"
    }

    r = requests.get("https://api.spotify.com/v1/search",params=params ,headers=headers)
    raw =json.loads(r.text)
    print(raw['artists']['items'][0].keys())

    sys.exit(0)
    
if __name__=='__main__':
    main()

실행결과는 아래와 같다.

dict_keys(['external_urls', 'followers', 'genres', 'href', 'id', 'images', 'name', 'popularity', 'type', 'uri'])

RDS에 table에 정의된 컬럼과 일치한다.

그러면 아래와 같이 코딩을 해서 RDS table에 insert하는 틀을 만들어본다.

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    params ={
        "q" : "Younha",
        "type" : "artist",
        "limit" : "1"
    }

    r = requests.get("https://api.spotify.com/v1/search",params=params ,headers=headers)
    raw =json.loads(r.text)
    artist_raw = raw['artists']['items'][0]

    if artist_raw['name'] == params['q']:
        artist = {
                'id' : artist_raw['id'],
                'name' : artist_raw['name'],
                'followers' : artist_raw['followers']['total'],
                'popularity' : artist_raw['popularity'],
                'url' : artist_raw['external_urls']['spotify'],
                'image_url' : artist_raw['images'][0]['url']
        }

    print(artist)

    query = """
        INSERT INTO pmstest.artists (id, name, followers, popularity, url, image_url)
        VALUES('{}','{}','{}','{}','{}','{}')
        ON DUPLICATE KEY UPDATE id = '{}', name = '{}',followers='{}',popularity='{}',url='{}',image_url='{}'
    """.format(
        artist['id'],
        artist['name'],
        artist['followers'],
        artist['popularity'],
        artist['url'],
        artist['image_url'],
        artist['id'],
        artist['name'],
        artist['followers'],
        artist['popularity'],
        artist['url'],
        artist['image_url']
    )

    print(query)
    
    sys.exit(0)
    
if __name__=='__main__':
    main()

실행결과는 아래와 같이 데이터가 잘 확인이 된다.

{'id': '6GwM5CHqhWXzG3l5kzRSAS', 'name': 'Younha', 'followers': 140615, 'popularity': 62, 'url': 'https://open.spotify.com/artist/6GwM5CHqhWXzG3l5kzRSAS', 'image_url': 'https://i.scdn.co/image/ab67616d0000b2734b89d54636763c641bce87e5'}

        INSERT INTO pmstest.artists (id, name, followers, popularity, url, image_url)
        VALUES('6GwM5CHqhWXzG3l5kzRSAS','Younha','140615','62','https://open.spotify.com/artist/6GwM5CHqhWXzG3l5kzRSAS','https://i.scdn.co/image/ab67616d0000b2734b89d54636763c641bce87e5')
        ON DUPLICATE KEY UPDATE id = '6GwM5CHqhWXzG3l5kzRSAS', name = 'Younha',followers='140615',popularity='62',url='https://open.spotify.com/artist/6GwM5CHqhWXzG3l5kzRSAS',image_url='https://i.scdn.co/image/ab67616d0000b2734b89d54636763c641bce87e5'

그러면 위에 데이터를 RDS에 insert를 아래 코딩과 같이 작성하여 실행해보자.

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    params ={
        "q" : "Younha",
        "type" : "artist",
        "limit" : "1"
    }

    r = requests.get("https://api.spotify.com/v1/search",params=params ,headers=headers)
    raw =json.loads(r.text)
    artist_raw = raw['artists']['items'][0]

    if artist_raw['name'] == params['q']:
        artist = {
                'id' : artist_raw['id'],
                'name' : artist_raw['name'],
                'followers' : artist_raw['followers']['total'],
                'popularity' : artist_raw['popularity'],
                'url' : artist_raw['external_urls']['spotify'],
                'image_url' : artist_raw['images'][0]['url']
        }

    query = """
        INSERT INTO pmstest.artists (id, name, followers, popularity, url, image_url)
        VALUES('{}','{}','{}','{}','{}','{}')
        ON DUPLICATE KEY UPDATE id = '{}', name = '{}',followers='{}',popularity='{}',url='{}',image_url='{}'
    """.format(
        artist['id'],
        artist['name'],
        artist['followers'],
        artist['popularity'],
        artist['url'],
        artist['image_url'],
        artist['id'],
        artist['name'],
        artist['followers'],
        artist['popularity'],
        artist['url'],
        artist['image_url']
    )

    cursor.execute(query)
    conn.commit()
    
    sys.exit(0)
    
if __name__=='__main__':
    main()

아래 그림과 같이 실제 RDS에 데이터가 잘 들어가는 것을 확인할 수 있다.

image

insert문을 아래 코드와 같이 함수화시켜보자

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    params ={
        "q" : "Younha",
        "type" : "artist",
        "limit" : "1"
    }

    r = requests.get("https://api.spotify.com/v1/search",params=params ,headers=headers)
    raw =json.loads(r.text)
    artist_raw = raw['artists']['items'][0]

    if artist_raw['name'] == params['q']:
        artist = {
                'id' : artist_raw['id'],
                'name' : artist_raw['name'],
                'followers' : artist_raw['followers']['total'],
                'popularity' : artist_raw['popularity'],
                'url' : artist_raw['external_urls']['spotify'],
                'image_url' : artist_raw['images'][0]['url']
        }

    insert_row(cursor, artist, 'pmstest.artists')
    conn.commit()

    return None

def insert_row(cursor, data, table):

    placeholders = ', '.join(['%s'] * len(data)) ## %s,%s,%s,%s,%s ...
    columns = ', '.join(data.keys())
    key_placeholders = ', '.join(['{0}=%s'.format(k) for k in data.keys()])
    sql = "INSERT INTO %s ( %s ) VALUES ( %s ) ON DUPLICATE KEY UPDATE %s" % (table, columns, placeholders, key_placeholders)
    ## sql은 아래와 같은 형태가 될 것이다.
    ## INSERT INTO artists ( id, name, followers, popularity, url, image_url ) VALUES ( %s, %s, %s, %s, %s, %s )
    ## ON DUPLICATE KEY UPDATE id=%s, name=%s, followers=%s, popularity=%s, url=%s, image_url=%s
    cursor.execute(sql, list(data.values())*2)


def get_headers(client_id, client_secret):

    endpoint = "https://accounts.spotify.com/api/token"
    encoded = base64.b64encode("{}:{}".format(client_id, client_secret).encode('utf-8')).decode('ascii')

    headers = {"Authorization": "Basic {}".format(encoded)}

    payload = {"grant_type": "client_credentials"}

    r = requests.post(endpoint, data=payload, headers=headers)

    access_token = json.loads(r.text)['access_token']

    headers = {"Authorization": "Bearer {}".format(access_token)}

    return headers

if __name__=='__main__':
    main()

그러면 아래그림과 같은 artist_list.csv에서 아티스트 이름을 불러와서 RDS에 spotify 데이터를 저장하는 코드를 구현해보자

image

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    ## Spotify Search API

    artists = []
    with open('artist_list.csv') as f:
        raw = csv.reader(f)
        for row in raw:
            artists.append(row[0])
    ## 위에 실행결과는 아래와 같이 될 것이다.
    ## artists = ['Younha', 'TAEYEON', 'BTS', 'HEIZE', 'BLACKPINK', 'EXO', 'IU', 'TWICE', 'Bolbbalgan4', 'ZICO']

    for a in artists:
        params = {
            "q": a,
            "type": "artist",
            "limit": "1"
        }

        r = requests.get("https://api.spotify.com/v1/search", params=params, headers=headers)

        raw = json.loads(r.text)

        artist = {}
        try:
            artist_raw = raw['artists']['items'][0]
            if artist_raw['name'] == params['q']:
                artist.update(
                    {
                        'id': artist_raw['id'],
                        'name': artist_raw['name'],
                        'followers': artist_raw['followers']['total'],
                        'popularity': artist_raw['popularity'],
                        'url': artist_raw['external_urls']['spotify'],
                        'image_url': artist_raw['images'][0]['url']
                    }
                )
                insert_row(cursor, artist, 'pmstest.artists')
            else:
                print("Can not {} artist match".format(a))
        except:
            logging.error('Can not {} Item found'.format(a))
            continue

    conn.commit()

    return None

def insert_row(cursor, data, table):
    placeholders = ', '.join(['%s'] * len(data)) ## %s,%s,%s,%s,%s ...
    columns = ', '.join(data.keys())
    key_placeholders = ', '.join(['{0}=%s'.format(k) for k in data.keys()])
    sql = "INSERT INTO %s ( %s ) VALUES ( %s ) ON DUPLICATE KEY UPDATE %s" % (table, columns, placeholders, key_placeholders)
    ## sql은 아래와 같은 형태가 될 것이다.
    ## INSERT INTO artists ( id, name, followers, popularity, url, image_url ) VALUES ( %s, %s, %s, %s, %s, %s )
    ## ON DUPLICATE KEY UPDATE id=%s, name=%s, followers=%s, popularity=%s, url=%s, image_url=%s
    cursor.execute(sql, list(data.values())*2)

def get_headers(client_id, client_secret):
    endpoint = "https://accounts.spotify.com/api/token"
    encoded = base64.b64encode("{}:{}".format(client_id, client_secret).encode('utf-8')).decode('ascii')
    headers = {"Authorization": "Basic {}".format(encoded)}
    payload = {"grant_type": "client_credentials"}
    r = requests.post(endpoint, data=payload, headers=headers)
    access_token = json.loads(r.text)['access_token']
    headers = {"Authorization": "Bearer {}".format(access_token)}
    return headers

if __name__=='__main__':
    main()

실행이 완료되면 아래 그림과 같이 RDS에 데이터들이 잘 들어오는 것을 확인할 수 있다.

image

지금은 10개로 했는데 그러면 500명의 아티스트 목록이 있는 artist_list.csv를 이용해서 50개씩 배치형태로 데이터를 가져와서 저장하는 것을 구현해보자.

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try :
        conn = pymysql.connect(host, user = username, passwd = password, db = database, port = port, use_unicode = True)
        cursor = conn.cursor()

    except :
        logging.error("could not connect to RDS")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    ## Spotify Search API

    artists = []
    with open('artist_list.csv','rt', encoding='UTF8') as f:
        ## 'rt', encoding='UTF8' 부분이 추가가 되었는데
        ## 이게 없으면 해당 500명짜리 아티스트 csv를 읽어올경우
        ## 아래와 같은 애러가 발생한다.
        ## UnicodeDecodeError: 'cp949' codec can't decode byte 0xbf in position 2: illegal multibyte sequence
        raw = csv.reader(f)
        for row in raw:
            artists.append(row[0])

    for a in artists:
        params = {
            "q": a,
            "type": "artist",
            "limit": "1"
        }

        r = requests.get("https://api.spotify.com/v1/search", params=params, headers=headers)

        raw = json.loads(r.text)

        artist = {}
        try:
            artist_raw = raw['artists']['items'][0]
            if artist_raw['name'] == params['q']:
                artist.update(
                    {
                        'id': artist_raw['id'],
                        'name': artist_raw['name'],
                        'followers': artist_raw['followers']['total'],
                        'popularity': artist_raw['popularity'],
                        'url': artist_raw['external_urls']['spotify'],
                        'image_url': artist_raw['images'][0]['url']
                    }
                )
                insert_row(cursor, artist, 'pmstest.artists')
            else:
                print("Can not {} artist match".format(a))
        except:
            logging.error('Can not {} Item found'.format(a))
            continue

    conn.commit()

    return None

def insert_row(cursor, data, table):
    placeholders = ', '.join(['%s'] * len(data)) ## %s,%s,%s,%s,%s ...
    columns = ', '.join(data.keys())
    key_placeholders = ', '.join(['{0}=%s'.format(k) for k in data.keys()])
    sql = "INSERT INTO %s ( %s ) VALUES ( %s ) ON DUPLICATE KEY UPDATE %s" % (table, columns, placeholders, key_placeholders)
    ## sql은 아래와 같은 형태가 될 것이다.
    ## INSERT INTO artists ( id, name, followers, popularity, url, image_url ) VALUES ( %s, %s, %s, %s, %s, %s )
    ## ON DUPLICATE KEY UPDATE id=%s, name=%s, followers=%s, popularity=%s, url=%s, image_url=%s
    cursor.execute(sql, list(data.values())*2)

def get_headers(client_id, client_secret):
    endpoint = "https://accounts.spotify.com/api/token"
    encoded = base64.b64encode("{}:{}".format(client_id, client_secret).encode('utf-8')).decode('ascii')
    headers = {"Authorization": "Basic {}".format(encoded)}
    payload = {"grant_type": "client_credentials"}
    r = requests.post(endpoint, data=payload, headers=headers)
    access_token = json.loads(r.text)['access_token']
    headers = {"Authorization": "Bearer {}".format(access_token)}
    return headers

if __name__=='__main__':
    main()

500명짜리 해당 csv 파일로 위의 코드를 실행하면 일단 실행결과는 아래와 같다.

아이템을 아예못찾는 경우도 있고, 아티스트를 못찾는 경우도 있다.

ERROR:root:Can not Danny Wilson & Gary Clark Item found
ERROR:root:Can not It Bites Item found
ERROR:root:Can not Japan & David Sylvian Item found
ERROR:root:Can not Joe Walsh / The James Gang Item found
ERROR:root:Can not The Nitty Gritty Dirt Band Item found
ERROR:root:Can not Paul McCartney and Wings Item found
Can not 10cc artist match
Can not Andre Rieu artist match
Can not Antonio Carlos Jobim artist match
Can not Beck artist match
Can not Blink-182 artist match
Can not Bob Marley artist match
Can not Booker T artist match
Can not Camel artist match
Can not Captain Beefheart artist match
Can not Caravan artist match
Can not Cat Stevens artist match
Can not The Commodores artist match
Can not DAngelo artist match
Can not Debarge artist match
Can not Derek And The Dominos artist match
Can not Dr Dre artist match
Can not EELS artist match
Can not Enigma artist match
Can not Faust artist match
Can not Free artist match
Can not Frida Lyngstad artist match
Can not Gene Vincent artist match
Can not George Thorogood artist match
Can not Guns N Roses artist match
Can not Hank Williams artist match
Can not Howlin Wolf artist match
Can not Jackson 5 artist match
Can not James artist match
Can not Janes Addiction artist match
Can not Jay-Z artist match
Can not Jeru the Damaja artist match
Can not John Mayall artist match
Can not Kiss artist match
Can not Kool And The Gang artist match
Can not Lady GaGa artist match
Can not Lee Scratch Perry artist match
Can not Lightnin Hopkins artist match
Can not Lloyd Cole artist match
Can not Mike & the Mechanics artist match
Can not N.W.A artist match
Can not OMD artist match
Can not PiL (Public Image Ltd) artist match
Can not Queens Of The Stone Age artist match
Can not Rainbow artist match
Can not Rick Nelson artist match
Can not Salt-n-Pepa artist match
Can not Sensational Alex Harvey Band artist match
Can not Sergio Mendes artist match
Can not Siouxsie & The Banshees artist match
Can not Sonny Boy Williamson artist match
Can not Stereo MCs artist match
Can not Texas artist match
Can not Van der Graaf Generator artist match
Can not Yello artist match
Can not Young Jeezy artist match

그래서 기존에 10개 정도 만든 kpop 아티스트 리스트와 합쳐져 505명의 데이터가 RDS에 저장된다.

데이터 예시는 아래와 같다.

image

그러면 아래와 같이 코드를 하고 실행을 해보자.

import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try:
        conn = pymysql.connect(host, user=username, passwd=password, db=database, port=port, use_unicode=True, charset='utf8')
        cursor = conn.cursor()
    except:
        logging.error("could not connect to rds")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    cursor.execute("SELECT id FROM artists")
    artists = []

    for (id, ) in cursor.fetchall():
        artists.append(id)

    artist_batch = [artists[i: i+50] for i in range(0, len(artists), 50)]
    ## 배치사이즈를 50으로 제한
    ## artist_batch = [[artist아이디 50개], ... ,[artist아이디 50개]]

    for i in artist_batch:

        ids = ','.join(i)
        URL = "https://api.spotify.com/v1/artists/?ids={}".format(ids)

        r = requests.get(URL, headers=headers)
        raw = json.loads(r.text)
        print(raw)
        print(len(raw['artists']))

    return None

def insert_row(cursor, data, table):
    placeholders = ', '.join(['%s'] * len(data)) ## %s,%s,%s,%s,%s ...
    columns = ', '.join(data.keys())
    key_placeholders = ', '.join(['{0}=%s'.format(k) for k in data.keys()])
    sql = "INSERT INTO %s ( %s ) VALUES ( %s ) ON DUPLICATE KEY UPDATE %s" % (table, columns, placeholders, key_placeholders)
    ## sql은 아래와 같은 형태가 될 것이다.
    ## INSERT INTO artists ( id, name, followers, popularity, url, image_url ) VALUES ( %s, %s, %s, %s, %s, %s )
    ## ON DUPLICATE KEY UPDATE id=%s, name=%s, followers=%s, popularity=%s, url=%s, image_url=%s
    cursor.execute(sql, list(data.values())*2)

def get_headers(client_id, client_secret):
    endpoint = "https://accounts.spotify.com/api/token"
    encoded = base64.b64encode("{}:{}".format(client_id, client_secret).encode('utf-8')).decode('ascii')
    headers = {"Authorization": "Basic {}".format(encoded)}
    payload = {"grant_type": "client_credentials"}
    r = requests.post(endpoint, data=payload, headers=headers)
    access_token = json.loads(r.text)['access_token']
    headers = {"Authorization": "Bearer {}".format(access_token)}
    return headers

if __name__=='__main__':
    main()

실행결과는 아래와 같다.

{'artists': [{'external_urls': {'spotify': 'https://open.spotify.com/artist/00FQb4jTyendYWaN8pK0wa'}, 'followers': {'href': None, 'total': 10490492}, 'genres': ['art pop', 'pop'], 'href': 'https://api.spotify.com/v1/artists/00FQb4jTyendYWaN8pK0wa', 'id': '00FQb4jTyendYWaN8pK0wa', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/6e8dc460cfb6b89d7970302259febd0aa73b38c6', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/bcdee6b17410b5d27d40bc114757e38125b00c84', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/0c50e5ae217b7a86f9f5114dc5e0f1beb8e9185d', 'width': 160}], 'name': 'Lana Del Rey', 'popularity': 87, 'type': 'artist', 'uri': 'spotify:artist:00FQb4jTyendYWaN8pK0wa'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/01C9OoXDvCKkGcf735Tcfo'}, 'followers': {'href': None, 'total': 319649}, 'genres': ['chanson', 'french rock'], 'href': 'https://api.spotify.com/v1/artists/01C9OoXDvCKkGcf735Tcfo', 'id': '01C9OoXDvCKkGcf735Tcfo', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/f259e1f28b3ad4130f3d63747425cd4349f65be6', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/2a2195f53b7309755f69b476081399033ed7abc4', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/dd8b3166719a31cae20b0da66a89518f3c28ecdc', 'width': 160}], 'name': 'Serge Gainsbourg', 'popularity': 62, 'type': 'artist', 'uri': 'spotify:artist:01C9OoXDvCKkGcf735Tcfo'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/02rd0anEWfMtF7iMku9uor'}, 'followers': {'href': None, 'total': 1139005}, 'genres': ['contemporary country', 'country', 'country dawn', 'oklahoma country'], 'href': 'https://api.spotify.com/v1/artists/02rd0anEWfMtF7iMku9uor', 'id': '02rd0anEWfMtF7iMku9uor', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/02bd6f8ffe0f3909be616ed36f7e106077ce7fb9', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/e5f988b4662a5dcdc65e60fcdff9f31a7230e783', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/e42a750e0c7edf90e692e3a940ed6808959a024d', 'width': 160}], 'name': 'Reba McEntire', 'popularity': 68, 'type': 'artist', 'uri': 'spotify:artist:02rd0anEWfMtF7iMku9uor'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/02uYdhMhCgdB49hZlYRm9o'}, 'followers': {'href': None, 'total': 386197}, 'genres': ['alternative rock', 'blues rock', 'garage rock', 'garage rock revival', 'modern blues rock', 'modern rock', 'palm desert scene', 'punk blues', 'rock'], 'href': 'https://api.spotify.com/v1/artists/02uYdhMhCgdB49hZlYRm9o', 'id': '02uYdhMhCgdB49hZlYRm9o', 'images': [{'height': 1000, 'url': 'https://i.scdn.co/image/9084649cb287a4cd52b6955fe9f5dd647fc4e431', 'width': 1000}, {'height': 640, 'url': 'https://i.scdn.co/image/40d4d2ecbefa83067c6e4c1575f59682fcc55a01', 'width': 640}, {'height': 200, 'url': 'https://i.scdn.co/image/c5bda32bcaefd65b004fec303555900f8be53fec', 'width': 200}, {'height': 64, 'url': 'https://i.scdn.co/image/4fd99c3f72971a5b67b653155fe00caf9289ba8c', 'width': 64}], 'name': 'Eagles Of Death Metal', 'popularity': 59, 'type': 'artist', 'uri': 'spotify:artist:02uYdhMhCgdB49hZlYRm9o'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/03r4iKL2g2442PT9n2UKsx'}, 'followers': {'href': None, 'total': 1613984}, 'genres': ['alternative rock', 'east coast hip hop', 'hip hop', 'old school hip hop', 'rap'], 'href': 'https://api.spotify.com/v1/artists/03r4iKL2g2442PT9n2UKsx', 'id': '03r4iKL2g2442PT9n2UKsx', 'images': [{'height': 771, 'url': 'https://i.scdn.co/image/705bcd56dc5dbf9ebc578a3ba8094e6d622862c2', 'width': 1000}, {'height': 494, 'url': 'https://i.scdn.co/image/060ef251f0e12353057c36fe94724b688b963dac', 'width': 640}, {'height': 154, 'url': 'https://i.scdn.co/image/eb9a69f247e84b9e9ce8b03f1ab5cca399b49cbc', 'width': 200}, {'height': 49, 'url': 'https://i.scdn.co/image/b6fafee2c4c169dadf039c2066ab77beb4c82b3e', 'width': 64}], 'name': 'Beastie Boys', 'popularity': 73, 'type': 'artist', 'uri': 'spotify:artist:03r4iKL2g2442PT9n2UKsx'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/03YhcM6fxypfwckPCQV8pQ'}, 'followers': {'href': None, 'total': 143971}, 'genres': ['bebop', 'contemporary post-bop', 'cool jazz', 'hard bop', 'jazz', 'jazz funk', 'jazz fusion', 'jazz guitar', 'soul jazz'], 'href': 'https://api.spotify.com/v1/artists/03YhcM6fxypfwckPCQV8pQ', 'id': '03YhcM6fxypfwckPCQV8pQ', 'images': [{'height': 713, 'url': 'https://i.scdn.co/image/e0fcfb2e4dbb9cb9c408ba7fad9bdd3526ef6ed8', 'width': 1000}, {'height': 456, 'url': 'https://i.scdn.co/image/556fb015a5411afb24f3d6691ac4f12847e08a14', 'width': 639}, {'height': 143, 'url': 'https://i.scdn.co/image/47b8c42a958dded335d85abe840b66581131be86', 'width': 200}, {'height': 46, 'url': 'https://i.scdn.co/image/5968a38e6973e52175187ce21d7bc9bbb940e9e2', 'width': 64}], 'name': 'Wes Montgomery', 'popularity': 56, 'type': 'artist', 'uri': 'spotify:artist:03YhcM6fxypfwckPCQV8pQ'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/04gDigrS5kc9YWfZHwBETP'}, 'followers': {'href': None, 'total': 24604026}, 'genres': ['pop', 'pop rock'], 'href': 'https://api.spotify.com/v1/artists/04gDigrS5kc9YWfZHwBETP', 'id': '04gDigrS5kc9YWfZHwBETP', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/608c7b23420c9556a7eabd9097f7e171a91d3871', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/57dba89591ae8a2a0f775e2168267c3a387a621c', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/35b1d8aadd0e89efe5ff11a6cd70367eb3bb669c', 'width': 160}], 'name': 'Maroon 5', 'popularity': 89, 'type': 'artist', 'uri': 'spotify:artist:04gDigrS5kc9YWfZHwBETP'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/04tBaW21jyUfeP5iqiKBVq'}, 'followers': {'href': None, 'total': 82040}, 'genres': ['art pop', 'art rock', 'baroque pop', 'experimental', 'melancholia', 'post-punk', 'singer-songwriter', 'slow core'], 'href': 'https://api.spotify.com/v1/artists/04tBaW21jyUfeP5iqiKBVq', 'id': '04tBaW21jyUfeP5iqiKBVq', 'images': [{'height': 333, 'url': 'https://i.scdn.co/image/90b31afd8391b7a8339474fe36cdc570a5003ea2', 'width': 300}, {'height': 222, 'url': 'https://i.scdn.co/image/64277226abdddb1084fc731532187aebf7989aee', 'width': 200}, {'height': 71, 'url': 'https://i.scdn.co/image/fc9e6cf2f2b1bb5279384ce66b43aead57fe90a8', 'width': 64}], 'name': 'Scott Walker', 'popularity': 50, 'type': 'artist', 'uri': 'spotify:artist:04tBaW21jyUfeP5iqiKBVq'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0543y7yrvny4KymoaneT4W'}, 'followers': {'href': None, 'total': 643647}, 'genres': ['album rock', 'art rock', 'blues rock', 'british blues', 'classic rock', 'country rock', 'folk rock', 'hard rock', 'heartland rock', 'mellow gold', 'rock', 'roots rock', 'soft rock', 'symphonic rock'], 'href': 'https://api.spotify.com/v1/artists/0543y7yrvny4KymoaneT4W', 'id': '0543y7yrvny4KymoaneT4W', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/f3e26a227c8d8fca2f7da7a20a7c23011fca5501', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/cb403ea6d1861e587ce3b3c1c11d849feb3b7d10', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/9ca9fd2798d5c411dcb8f6346808fa40f0e268b5', 'width': 160}], 'name': 'Peter Frampton', 'popularity': 61, 'type': 'artist', 'uri': 'spotify:artist:0543y7yrvny4KymoaneT4W'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/05E3NBxNMdnrPtxF9oraJm'}, 'followers': {'href': None, 'total': 90684}, 'genres': ['bebop', 'big band', 'contemporary post-bop', 'cool jazz', 'hard bop', 'jazz', 'jazz saxophone', 'soul jazz', 'stride', 'swing', 'vocal jazz'], 'href': 'https://api.spotify.com/v1/artists/05E3NBxNMdnrPtxF9oraJm', 'id': '05E3NBxNMdnrPtxF9oraJm', 'images': [{'height': 862, 'url': 'https://i.scdn.co/image/59f160b9b2e5803e766188270977f15af20f8bf1', 'width': 688}, {'height': 802, 'url': 'https://i.scdn.co/image/bc898aaca97929afde931e8c2128268864575860', 'width': 640}, {'height': 251, 'url': 'https://i.scdn.co/image/91410a93926a683ab7729d4689f06bbaa50c752b', 'width': 200}, {'height': 80, 'url': 'https://i.scdn.co/image/46cc83ad5edd39797bdbe81ad71a6f8aefd03139', 'width': 64}], 'name': 'Lester Young', 'popularity': 52, 'type': 'artist', 'uri': 'spotify:artist:05E3NBxNMdnrPtxF9oraJm'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02'}, 'followers': {'href': None, 'total': 29475436}, 'genres': ['dance pop', 'pop', 'post-teen pop'], 'href': 'https://api.spotify.com/v1/artists/06HL4z0CvFAxyc27GXpf02', 'id': '06HL4z0CvFAxyc27GXpf02', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/62b33d12e2b9a033cf77585f6e3d4b2c6b3a63a1', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/9ab124f3323d161f87fc9b7f8b82ab1717483b3a', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/d28b46cd7e1b7336d1688d462085535963a77311', 'width': 160}], 'name': 'Taylor Swift', 'popularity': 92, 'type': 'artist', 'uri': 'spotify:artist:06HL4z0CvFAxyc27GXpf02'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/06nevPmNVfWUXyZkccahL8'}, 'followers': {'href': None, 'total': 380681}, 'genres': ['adult standards', 'contemporary vocal jazz', 'neo soul', 'soul', 'vocal jazz'], 'href': 'https://api.spotify.com/v1/artists/06nevPmNVfWUXyZkccahL8', 'id': '06nevPmNVfWUXyZkccahL8', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/157c5ac9133097d16e89b6fdf9cf9f346941f2db', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/cac167c27be12427861d4487dfadd86671b05f59', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/eb4e72e03ff21427d389dff58644ee728f5c2ac2', 'width': 160}], 'name': 'Gregory Porter', 'popularity': 66, 'type': 'artist', 'uri': 'spotify:artist:06nevPmNVfWUXyZkccahL8'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/06nsZ3qSOYZ2hPVIMcr1IN'}, 'followers': {'href': None, 'total': 407481}, 'genres': ['blues', 'blues rock', 'classic rock', 'country rock', 'folk rock', 'mellow gold', 'modern blues', 'rock', 'roots rock'], 'href': 'https://api.spotify.com/v1/artists/06nsZ3qSOYZ2hPVIMcr1IN', 'id': '06nsZ3qSOYZ2hPVIMcr1IN', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/63c3a9c0a7029e04935d8fc6c7eb1bef0a196c58', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/cad2ef50c2e83dc3cf10550c92affedf9463eee5', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ee18eba97af98a7cddc0a877f066bd565ba30152', 'width': 160}], 'name': 'J.J. Cale', 'popularity': 65, 'type': 'artist', 'uri': 'spotify:artist:06nsZ3qSOYZ2hPVIMcr1IN'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/085pc2PYOi8bGKj0PNjekA'}, 'followers': {'href': None, 'total': 2942155}, 'genres': ['dance pop', 'pop', 'pop rap', 'post-teen pop'], 'href': 'https://api.spotify.com/v1/artists/085pc2PYOi8bGKj0PNjekA', 'id': '085pc2PYOi8bGKj0PNjekA', 'images': [{'height': 1000, 'url': 'https://i.scdn.co/image/d9e6047498dc100048c4597be2aa1d20ebf6df40', 'width': 1000}, {'height': 640, 'url': 'https://i.scdn.co/image/ffb9f989856095ea16e38a0898e424294b88903c', 'width': 640}, {'height': 200, 'url': 'https://i.scdn.co/image/9158bbe4ccd59e97461be0714563b6a5a413af84', 'width': 200}, {'height': 64, 'url': 'https://i.scdn.co/image/761fa85a5fda519a84a8fb12a353cbd8431666cb', 'width': 64}], 'name': 'will.i.am', 'popularity': 77, 'type': 'artist', 'uri': 'spotify:artist:085pc2PYOi8bGKj0PNjekA'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/08avsqaGIlK2x3i2Cu7rKH'}, 'followers': {'href': None, 'total': 173105}, 'genres': ['blues', 'blues rock', 'british blues', 'classic rock', 'electric blues', 'roots rock'], 'href': 'https://api.spotify.com/v1/artists/08avsqaGIlK2x3i2Cu7rKH', 'id': '08avsqaGIlK2x3i2Cu7rKH', 'images': [{'height': 733, 'url': 'https://i.scdn.co/image/a13eee07307adc70fe177f0fa73e935cb909afe6', 'width': 550}, {'height': 267, 'url': 'https://i.scdn.co/image/c27953e852d724d47227fb792e376ef8fb274597', 'width': 200}, {'height': 85, 'url': 'https://i.scdn.co/image/9501c73796dede00f3115adfe6d780b8cc689f16', 'width': 64}], 'name': 'Keith Richards', 'popularity': 47, 'type': 'artist', 'uri': 'spotify:artist:08avsqaGIlK2x3i2Cu7rKH'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/09C0xjtosNAIXP36wTnWxd'}, 'followers': {'href': None, 'total': 290667}, 'genres': ['adult standards', 'brill building pop', 'louisiana blues', 'lounge', 'new orleans blues', 'piano blues', 'rhythm and blues', 'rock-and-roll', 'rockabilly', 'soul'], 'href': 'https://api.spotify.com/v1/artists/09C0xjtosNAIXP36wTnWxd', 'id': '09C0xjtosNAIXP36wTnWxd', 'images': [{'height': 1170, 'url': 'https://i.scdn.co/image/795ae538a48341d36523c1644b0da31a542db7e5', 'width': 1000}, {'height': 749, 'url': 'https://i.scdn.co/image/87c3cd1c4917dc6961fafa5b679fafc7c00cb1eb', 'width': 640}, {'height': 234, 'url': 'https://i.scdn.co/image/e1ecb1edaf668afe7eb974bae90fd7bf00679108', 'width': 200}, {'height': 75, 'url': 'https://i.scdn.co/image/aa497e48f8054c5a5838e9372bdceaa38237f8a3', 'width': 64}], 'name': 'Fats Domino', 'popularity': 59, 'type': 'artist', 'uri': 'spotify:artist:09C0xjtosNAIXP36wTnWxd'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0BvkDsjIUla7X0k6CSWh1I'}, 'followers': {'href': None, 'total': 5326808}, 'genres': ['contemporary country', 'country', 'country road'], 'href': 'https://api.spotify.com/v1/artists/0BvkDsjIUla7X0k6CSWh1I', 'id': '0BvkDsjIUla7X0k6CSWh1I', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/7d0807400f9076bd4c16d05ccec24c4ae1675e16', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/0e8ef130f7c00f720219f1a6bc391d578667bdce', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/cdc356e89f147d2c39ff24fbf8b1d1b53e734e70', 'width': 160}], 'name': 'Luke Bryan', 'popularity': 80, 'type': 'artist', 'uri': 'spotify:artist:0BvkDsjIUla7X0k6CSWh1I'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0bvRYuXRvd14RYEE7c0PRW'}, 'followers': {'href': None, 'total': 26358}, 'genres': ['dub', 'dub poetry', 'reggae', 'roots reggae', 'ska'], 'href': 'https://api.spotify.com/v1/artists/0bvRYuXRvd14RYEE7c0PRW', 'id': '0bvRYuXRvd14RYEE7c0PRW', 'images': [{'height': 1500, 'url': 'https://i.scdn.co/image/f79bfd0adfc7e52d87b0309ee8920ff074a766ee', 'width': 1000}, {'height': 960, 'url': 'https://i.scdn.co/image/7cb4efa9a93cc536527d7ef7a80a76d101f82025', 'width': 640}, {'height': 300, 'url': 'https://i.scdn.co/image/8b8dce49480ae35dae7c014910d09cf1b18e983b', 'width': 200}, {'height': 96, 'url': 'https://i.scdn.co/image/67f40088a15cc6d9e905c88bba30ce7943de322f', 'width': 64}], 'name': 'Linton Kwesi Johnson', 'popularity': 45, 'type': 'artist', 'uri': 'spotify:artist:0bvRYuXRvd14RYEE7c0PRW'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0C0XlULifJtAgn6ZNCW2eu'}, 'followers': {'href': None, 'total': 5326377}, 'genres': ['modern rock', 'permanent wave', 'rock'], 'href': 'https://api.spotify.com/v1/artists/0C0XlULifJtAgn6ZNCW2eu', 'id': '0C0XlULifJtAgn6ZNCW2eu', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/c85f1ea9f92dc0cc43965a0c727c4a1cdd1c2540', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ed9a0918a792c5af1ca3461f40670016a0c8f854', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/fb8fcdac51e0b606124f2d5005107c3466cbc5ad', 'width': 160}], 'name': 'The Killers', 'popularity': 81, 'type': 'artist', 'uri': 'spotify:artist:0C0XlULifJtAgn6ZNCW2eu'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0cc6vw3VN8YlIcvr1v7tBL'}, 'followers': {'href': None, 'total': 2569064}, 'genres': ['album rock', 'glam metal', 'hard rock', 'metal', 'rock', 'sleaze rock'], 'href': 'https://api.spotify.com/v1/artists/0cc6vw3VN8YlIcvr1v7tBL', 'id': '0cc6vw3VN8YlIcvr1v7tBL', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/82e32119f6232816abbf017a4bbb5481c5cb9d44', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/6721203f85506df49b96a361af155a78e9ed8310', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/31cf53a13e649f519154b47d03f913acd653a1ba', 'width': 160}], 'name': 'Mötley Crüe', 'popularity': 75, 'type': 'artist', 'uri': 'spotify:artist:0cc6vw3VN8YlIcvr1v7tBL'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0cpt0xebTXatYk3KvnrU9m'}, 'followers': {'href': None, 'total': 39407}, 'genres': ['reggae', 'uk reggae'], 'href': 'https://api.spotify.com/v1/artists/0cpt0xebTXatYk3KvnrU9m', 'id': '0cpt0xebTXatYk3KvnrU9m', 'images': [{'height': 634, 'url': 'https://i.scdn.co/image/a67435d1de7eaa4aa8d0ce2f72524e2afb1dcf2e', 'width': 1000}, {'height': 406, 'url': 'https://i.scdn.co/image/4e686295c493609d3be37b9b26b64f145be18f18', 'width': 640}, {'height': 127, 'url': 'https://i.scdn.co/image/1148260b47b7dc9cb39b6f3ada42d2865f137599', 'width': 200}, {'height': 41, 'url': 'https://i.scdn.co/image/27d7d0e809d44e7958952bd0b6785b999a9cd837', 'width': 64}], 'name': 'Pato Banton', 'popularity': 49, 'type': 'artist', 'uri': 'spotify:artist:0cpt0xebTXatYk3KvnrU9m'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0cQbJU1aAzvbEmTuljWLlF'}, 'followers': {'href': None, 'total': 1579488}, 'genres': ['alternative rock', 'dance pop', 'permanent wave', 'pop rock', 'post-grunge'], 'href': 'https://api.spotify.com/v1/artists/0cQbJU1aAzvbEmTuljWLlF', 'id': '0cQbJU1aAzvbEmTuljWLlF', 'images': [{'height': 667, 'url': 'https://i.scdn.co/image/f7e39e0ca7a4ba897150247190fb27b6ae6e0318', 'width': 1000}, {'height': 427, 'url': 'https://i.scdn.co/image/062f558dbf9cd7d8f820a094b84d7c6513c1ef8f', 'width': 640}, {'height': 133, 'url': 'https://i.scdn.co/image/6d74978edc9ec01cec160888e62d986b80aaea51', 'width': 200}, {'height': 43, 'url': 'https://i.scdn.co/image/3877d00cef020004a2b8fcb9d69d85981f0b1f38', 'width': 64}], 'name': 'No Doubt', 'popularity': 70, 'type': 'artist', 'uri': 'spotify:artist:0cQbJU1aAzvbEmTuljWLlF'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0dgnITyIAN4NrmUVisvxHU'}, 'followers': {'href': None, 'total': 525298}, 'genres': ['album rock', 'classic rock', 'glam metal', 'hard rock', 'post-grunge', 'rock', 'sacramento indie'], 'href': 'https://api.spotify.com/v1/artists/0dgnITyIAN4NrmUVisvxHU', 'id': '0dgnITyIAN4NrmUVisvxHU', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/bd170d2b2c6d61ad7d54365f4a32e4d8940086ac', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/3533092ba9cf284ad6a611952032c21f140540c2', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/afc9c88f8e964a56d459d2b2877207cda713390d', 'width': 160}], 'name': 'Tesla', 'popularity': 58, 'type': 'artist', 'uri': 'spotify:artist:0dgnITyIAN4NrmUVisvxHU'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0ECwFtbIWEVNwjlrfc6xoL'}, 'followers': {'href': None, 'total': 4939910}, 'genres': ['album rock', 'classic rock', 'country rock', 'folk rock', 'heartland rock', 'mellow gold', 'rock', 'soft rock', 'yacht rock'], 'href': 'https://api.spotify.com/v1/artists/0ECwFtbIWEVNwjlrfc6xoL', 'id': '0ECwFtbIWEVNwjlrfc6xoL', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/6b215464b769958ef1d7d9f163e3f49ebacf8842', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/2cfb3ecbce024ccb5e42b6f1b23683a3868fa804', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/f6e8c5d35816033e9e64f59adf96bb139b5a8206', 'width': 160}], 'name': 'Eagles', 'popularity': 79, 'type': 'artist', 'uri': 'spotify:artist:0ECwFtbIWEVNwjlrfc6xoL'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0EdvGhlC1FkGItLOWQzG4J'}, 'followers': {'href': None, 'total': 1631541}, 'genres': ['reggae fusion', 'ska mexicano', 'ska punk'], 'href': 'https://api.spotify.com/v1/artists/0EdvGhlC1FkGItLOWQzG4J', 'id': '0EdvGhlC1FkGItLOWQzG4J', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/2f51c42ecd190a65204ea323d2eecdc0987b71b6', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/86ab569f538d934092600b0e84006dc31e3e45ab', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/19238e18afd3bf7774a0efc652df3f48d630054e', 'width': 160}], 'name': 'Sublime', 'popularity': 75, 'type': 'artist', 'uri': 'spotify:artist:0EdvGhlC1FkGItLOWQzG4J'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0F3Aew9DSd6fb6192K1K0Y'}, 'followers': {'href': None, 'total': 196086}, 'genres': ['contemporary jazz', 'contemporary post-bop', 'cool jazz', 'ecm-style jazz', 'jazz', 'jazz fusion', 'jazz piano'], 'href': 'https://api.spotify.com/v1/artists/0F3Aew9DSd6fb6192K1K0Y', 'id': '0F3Aew9DSd6fb6192K1K0Y', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/fa582c5e13fd56cfd7cafca75c59eb8cc14f2d5d', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/c4ccce8cbacbe75dc9301ba0fb01e038fcce7ba1', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/19d41261ca5ab127afb17cc7faf306dec4a27130', 'width': 160}], 'name': 'Keith Jarrett', 'popularity': 60, 'type': 'artist', 'uri': 'spotify:artist:0F3Aew9DSd6fb6192K1K0Y'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0FI0kxP0BWurTz8cB8BBug'}, 'followers': {'href': None, 'total': 778358}, 'genres': ['classic rock', 'folk rock', 'mellow gold', 'soft rock'], 'href': 'https://api.spotify.com/v1/artists/0FI0kxP0BWurTz8cB8BBug', 'id': '0FI0kxP0BWurTz8cB8BBug', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/fc0d496b55103b6457a2a79bef935f105a563bc8', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/51935fe845828595a5f06414cf9f311f345a54bf', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/906321b938ffdc765ff3da3f63817d967f1bb4c8', 'width': 160}], 'name': 'Mark Knopfler', 'popularity': 67, 'type': 'artist', 'uri': 'spotify:artist:0FI0kxP0BWurTz8cB8BBug'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0FMucZsEnCxs5pqBjHjIc8'}, 'followers': {'href': None, 'total': 248995}, 'genres': ['adult standards', 'bebop', 'bossa nova', 'cool jazz', 'jazz', 'jazz saxophone', 'latin jazz', 'vocal jazz'], 'href': 'https://api.spotify.com/v1/artists/0FMucZsEnCxs5pqBjHjIc8', 'id': '0FMucZsEnCxs5pqBjHjIc8', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/a8f4878a1dfe7b31fada993e0c8366e32926597f', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ecb63813bbb38fbfca71a8bf7e82dd906c14d60e', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/e4a6b51d62c2da88ba7a2d73435ca814ca906086', 'width': 160}], 'name': 'Stan Getz', 'popularity': 68, 'type': 'artist', 'uri': 'spotify:artist:0FMucZsEnCxs5pqBjHjIc8'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0FrpdcVlJQqibaz5HfBUrL'}, 'followers': {'href': None, 'total': 678384}, 'genres': ['disco', 'funk', 'motown', 'post-disco', 'quiet storm', 'soul', 'synth funk'], 'href': 'https://api.spotify.com/v1/artists/0FrpdcVlJQqibaz5HfBUrL', 'id': '0FrpdcVlJQqibaz5HfBUrL', 'images': [{'height': 1145, 'url': 'https://i.scdn.co/image/e6c035ae9b2a8dd5cf6a3c5f4a0b274d5ff2a605', 'width': 1000}, {'height': 733, 'url': 'https://i.scdn.co/image/aa4cf47f4d71f91fe70f61bb703f35dc1afeb185', 'width': 640}, {'height': 229, 'url': 'https://i.scdn.co/image/3ce5793e0e2ab9e3dbc03c1cb23d538c8b86f1b7', 'width': 200}, {'height': 73, 'url': 'https://i.scdn.co/image/f52762298c22a9c9a82363a96741b726a44c497e', 'width': 64}], 'name': 'Rick James', 'popularity': 63, 'type': 'artist', 'uri': 'spotify:artist:0FrpdcVlJQqibaz5HfBUrL'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0fyqyjD7pbaVzbu94ylWQR'}, 'followers': {'href': None, 'total': 126365}, 'genres': ['album rock', 'classic rock', 'country rock', 'folk', 'folk rock', 'mellow gold', 'roots rock', 'soft rock'], 'href': 'https://api.spotify.com/v1/artists/0fyqyjD7pbaVzbu94ylWQR', 'id': '0fyqyjD7pbaVzbu94ylWQR', 'images': [{'height': 660, 'url': 'https://i.scdn.co/image/6747986aaed37e5ba0ebe69d8f4a1efde0892e19', 'width': 999}, {'height': 423, 'url': 'https://i.scdn.co/image/8f808de6ce1199bf374db32a04283d79e5bb4673', 'width': 640}, {'height': 132, 'url': 'https://i.scdn.co/image/043223d93deee381510a5ffef6fbce100a6d04e2', 'width': 200}, {'height': 42, 'url': 'https://i.scdn.co/image/9e860268fcc8462c1580cdc3f5eca5f1343e3474', 'width': 64}], 'name': 'Poco', 'popularity': 50, 'type': 'artist', 'uri': 'spotify:artist:0fyqyjD7pbaVzbu94ylWQR'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0h9smro0z3HqUbD94jotU8'}, 'followers': {'href': None, 'total': 646225}, 'genres': ['classic soul', 'disco', 'funk', 'motown', 'quiet storm', 'soul', 'southern soul'], 'href': 'https://api.spotify.com/v1/artists/0h9smro0z3HqUbD94jotU8', 'id': '0h9smro0z3HqUbD94jotU8', 'images': [{'height': 1159, 'url': 'https://i.scdn.co/image/60683dee3e26a764667ca7543c6ba557961524c7', 'width': 1000}, {'height': 741, 'url': 'https://i.scdn.co/image/77926b1442d85d5d64fe767c909f58d94e8d54f6', 'width': 640}, {'height': 232, 'url': 'https://i.scdn.co/image/a4a093971d5c32164eb5ece33beb44e761bb80e2', 'width': 200}, {'height': 74, 'url': 'https://i.scdn.co/image/467db56affc87edb25050d47dd73635bb678e7f4', 'width': 64}], 'name': 'Smokey Robinson', 'popularity': 61, 'type': 'artist', 'uri': 'spotify:artist:0h9smro0z3HqUbD94jotU8'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0hCNtLu0JehylgoiP8L4Gh'}, 'followers': {'href': None, 'total': 17672559}, 'genres': ['dance pop', 'hip pop', 'pop', 'pop rap', 'post-teen pop', 'queens hip hop'], 'href': 'https://api.spotify.com/v1/artists/0hCNtLu0JehylgoiP8L4Gh', 'id': '0hCNtLu0JehylgoiP8L4Gh', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/1a6476028ced225730a1fe889af3b963dd260259', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/858b9cf934b3fa92033c9cb0771aeb6903fb5355', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/69f90b8fe0ddaeb6becb0002e2372ffa6bfa9fc4', 'width': 160}], 'name': 'Nicki Minaj', 'popularity': 92, 'type': 'artist', 'uri': 'spotify:artist:0hCNtLu0JehylgoiP8L4Gh'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0hF0PwB04hnXfYMiZWfJzy'}, 'followers': {'href': None, 'total': 110205}, 'genres': ['brill building pop', 'classic soul', 'motown', 'soul', 'southern soul'], 'href': 'https://api.spotify.com/v1/artists/0hF0PwB04hnXfYMiZWfJzy', 'id': '0hF0PwB04hnXfYMiZWfJzy', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab67616d0000b273d5f1291b6078c8ca95285865', 'width': 640}, {'height': 300, 'url': 'https://i.scdn.co/image/ab67616d00001e02d5f1291b6078c8ca95285865', 'width': 300}, {'height': 64, 'url': 'https://i.scdn.co/image/ab67616d00004851d5f1291b6078c8ca95285865', 'width': 64}], 'name': 'Jimmy Ruffin', 'popularity': 52, 'type': 'artist', 'uri': 'spotify:artist:0hF0PwB04hnXfYMiZWfJzy'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0IecGJbdBeYSOVtSPRehh5'}, 'followers': {'href': None, 'total': 35669}, 'genres': ['classic soul', 'funk', 'motown', 'soul', 'southern soul'], 'href': 'https://api.spotify.com/v1/artists/0IecGJbdBeYSOVtSPRehh5', 'id': '0IecGJbdBeYSOVtSPRehh5', 'images': [{'height': 1000, 'url': 'https://i.scdn.co/image/49bc10d9841773e35824e64018df6bcffe20be8b', 'width': 1000}, {'height': 640, 'url': 'https://i.scdn.co/image/2844d12d73df54435d13122a37286fe532de3a07', 'width': 640}, {'height': 200, 'url': 'https://i.scdn.co/image/6187ef7f25d7c98f41acbb46f4ece2f3b5ecf81a', 'width': 200}, {'height': 64, 'url': 'https://i.scdn.co/image/22074964a11f701c1d510d60ff23c418140853b4', 'width': 64}], 'name': 'Billy Preston', 'popularity': 52, 'type': 'artist', 'uri': 'spotify:artist:0IecGJbdBeYSOVtSPRehh5'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0iHb0mCbqZTYeb4y9Pirrd'}, 'followers': {'href': None, 'total': 695278}, 'genres': ['alternative metal', 'alternative rock', 'grunge', 'hard rock', 'post-grunge', 'rock', 'supergroup'], 'href': 'https://api.spotify.com/v1/artists/0iHb0mCbqZTYeb4y9Pirrd', 'id': '0iHb0mCbqZTYeb4y9Pirrd', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/78d5dbf2f02b71768400bc471356f6aabd8f0a57', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/fc22bc9f1d4ffe9d48f1be144777415550bcd8c9', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/944bff3c044dc32414b7f99eb60af9404cbab69d', 'width': 160}], 'name': 'Temple Of The Dog', 'popularity': 60, 'type': 'artist', 'uri': 'spotify:artist:0iHb0mCbqZTYeb4y9Pirrd'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0iOVhN3tnSvgDbcg25JoJb'}, 'followers': {'href': None, 'total': 1001773}, 'genres': ['adult standards', 'jazz blues', 'soul', 'soul blues', 'torch song', 'vocal jazz'], 'href': 'https://api.spotify.com/v1/artists/0iOVhN3tnSvgDbcg25JoJb', 'id': '0iOVhN3tnSvgDbcg25JoJb', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/4cf0ce631f5c4b189648a4fde4f95a986be27580', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/cc9cc776cbc11a89900931ede0c5e20845ff8602', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/d4128c13c57573c441b0e215e0e7cfd6e5146499', 'width': 160}], 'name': 'Etta James', 'popularity': 69, 'type': 'artist', 'uri': 'spotify:artist:0iOVhN3tnSvgDbcg25JoJb'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0J9mbwg4BquN4XlHzdMK3X'}, 'followers': {'href': None, 'total': 151597}, 'genres': ['europop'], 'href': 'https://api.spotify.com/v1/artists/0J9mbwg4BquN4XlHzdMK3X', 'id': '0J9mbwg4BquN4XlHzdMK3X', 'images': [{'height': 330, 'url': 'https://i.scdn.co/image/1052c6690062dc1ad53d8562b37cc48df06e2c46', 'width': 219}, {'height': 301, 'url': 'https://i.scdn.co/image/c74b486d55959d2628d26b6cde353a97f1a7cbaf', 'width': 200}, {'height': 96, 'url': 'https://i.scdn.co/image/75bf08ec22506ca0501c80a6d88ca907472afdd4', 'width': 64}], 'name': 'Demis Roussos', 'popularity': 56, 'type': 'artist', 'uri': 'spotify:artist:0J9mbwg4BquN4XlHzdMK3X'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0JDkhL4rjiPNEp92jAgJnS'}, 'followers': {'href': None, 'total': 977129}, 'genres': ['adult standards', 'brill building pop', 'classic rock', 'folk rock', 'mellow gold', 'rock', 'rock-and-roll', 'rockabilly', 'soft rock'], 'href': 'https://api.spotify.com/v1/artists/0JDkhL4rjiPNEp92jAgJnS', 'id': '0JDkhL4rjiPNEp92jAgJnS', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/846e8808178b1b66a5220f947185dc91b89f6f5b', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/02f851191e49bdd2fa6ea0f48249c29bf3f83e02', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/eb0071dff0b03dc8d7b3f91c92277c0480c30b32', 'width': 160}], 'name': 'Roy Orbison', 'popularity': 70, 'type': 'artist', 'uri': 'spotify:artist:0JDkhL4rjiPNEp92jAgJnS'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0JM134st8VY7Ld9T2wQiH0'}, 'followers': {'href': None, 'total': 84800}, 'genres': ['bebop', 'big band', 'contemporary post-bop', 'cool jazz', 'hard bop', 'jazz', 'jazz saxophone', 'soul jazz', 'stride', 'swing', 'vocal jazz'], 'href': 'https://api.spotify.com/v1/artists/0JM134st8VY7Ld9T2wQiH0', 'id': '0JM134st8VY7Ld9T2wQiH0', 'images': [{'height': 777, 'url': 'https://i.scdn.co/image/9621e2a97694c5d7cdf6770ee9b82e0b9c729b10', 'width': 596}, {'height': 261, 'url': 'https://i.scdn.co/image/1024696b87ffd18c8141c7b2e96a84af90147d2f', 'width': 200}, {'height': 83, 'url': 'https://i.scdn.co/image/9e5baea30427c9a087567ea9197038376727697c', 'width': 64}], 'name': 'Coleman Hawkins', 'popularity': 51, 'type': 'artist', 'uri': 'spotify:artist:0JM134st8VY7Ld9T2wQiH0'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0jYKX08u1XxmHrl5TdM2QZ'}, 'followers': {'href': None, 'total': 56947}, 'genres': ['brill building pop', 'british invasion', 'bubblegum pop', 'classic uk pop', 'merseybeat', 'rock-and-roll'], 'href': 'https://api.spotify.com/v1/artists/0jYKX08u1XxmHrl5TdM2QZ', 'id': '0jYKX08u1XxmHrl5TdM2QZ', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/be4f9a496f4c4cfd8afd3642fc665b2a29c1083d', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/935cf8fc2373df25ab657929b82aa7b955c809a3', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/b751e8dcc59f0b05ce226039d99b4127166b4ee0', 'width': 160}], 'name': 'Lulu', 'popularity': 56, 'type': 'artist', 'uri': 'spotify:artist:0jYKX08u1XxmHrl5TdM2QZ'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0k17h0D3J5VfsdmQ1iZtE9'}, 'followers': {'href': None, 'total': 12180275}, 'genres': ['album rock', 'art rock', 'classic rock', 'progressive rock', 'psychedelic rock', 'rock', 'symphonic rock'], 'href': 'https://api.spotify.com/v1/artists/0k17h0D3J5VfsdmQ1iZtE9', 'id': '0k17h0D3J5VfsdmQ1iZtE9', 'images': [{'height': 977, 'url': 'https://i.scdn.co/image/e69f71e2be4b67b82af90fb8e9d805715e0684fa', 'width': 1000}, {'height': 625, 'url': 'https://i.scdn.co/image/d011c95081cd9a329e506abd7ded47535d524a07', 'width': 640}, {'height': 195, 'url': 'https://i.scdn.co/image/f0a39a8a196a87a7236bdcf8a8708f6d5d3547cc', 'width': 200}, {'height': 63, 'url': 'https://i.scdn.co/image/ec1fb7127168dbaa962404031409c5a293b95ec6', 'width': 64}], 'name': 'Pink Floyd', 'popularity': 84, 'type': 'artist', 'uri': 'spotify:artist:0k17h0D3J5VfsdmQ1iZtE9'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0kbYTNQb4Pb1rPbbaF0pT4'}, 'followers': {'href': None, 'total': 1796021}, 'genres': ['bebop', 'contemporary post-bop', 'cool jazz', 'hard bop', 'jazz', 'jazz fusion', 'jazz trumpet'], 'href': 'https://api.spotify.com/v1/artists/0kbYTNQb4Pb1rPbbaF0pT4', 'id': '0kbYTNQb4Pb1rPbbaF0pT4', 'images': [{'height': 1000, 'url': 'https://i.scdn.co/image/423e826b3c1b23930a255d7cbc2daf733f795507', 'width': 1000}, {'height': 640, 'url': 'https://i.scdn.co/image/a318c54208af38364d131a54ced2416423696018', 'width': 640}, {'height': 200, 'url': 'https://i.scdn.co/image/8496e6ea230dd47311d85dcf860015792f5ada42', 'width': 200}, {'height': 64, 'url': 'https://i.scdn.co/image/b1af952a7fb8ac2c4467868d61b5752fc1a01cf0', 'width': 64}], 'name': 'Miles Davis', 'popularity': 68, 'type': 'artist', 'uri': 'spotify:artist:0kbYTNQb4Pb1rPbbaF0pT4'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0kV0e99xlTJcLKSu8KrLyp'}, 'followers': {'href': None, 'total': 19915}, 'genres': ['neo-classical', 'swedish jazz'], 'href': 'https://api.spotify.com/v1/artists/0kV0e99xlTJcLKSu8KrLyp', 'id': '0kV0e99xlTJcLKSu8KrLyp', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/23160f155d9f85e04d9af4c1f90b316c908a657a', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/597df31b8ef66b7848a653619b0659f871875f65', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/a4e36e5cdb2de1b71c5685692ad50ae1da0ae543', 'width': 160}], 'name': 'Benny Andersson', 'popularity': 53, 'type': 'artist', 'uri': 'spotify:artist:0kV0e99xlTJcLKSu8KrLyp'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0L8ExT028jH3ddEcZwqJJ5'}, 'followers': {'href': None, 'total': 13303277}, 'genres': ['alternative rock', 'funk metal', 'funk rock', 'permanent wave', 'post-grunge', 'rock'], 'href': 'https://api.spotify.com/v1/artists/0L8ExT028jH3ddEcZwqJJ5', 'id': '0L8ExT028jH3ddEcZwqJJ5', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/89bc3c14aa2b4f250033ffcf5f322b2a553d9331', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/7251ac7f3c0262cfcfad32e214deda639a2b4b46', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/8def8c4db6061deb04daca08e43bcde57181ec8b', 'width': 160}], 'name': 'Red Hot Chili Peppers', 'popularity': 85, 'type': 'artist', 'uri': 'spotify:artist:0L8ExT028jH3ddEcZwqJJ5'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0L9xkvBPcEp1nrhDrodxc5'}, 'followers': {'href': None, 'total': 368955}, 'genres': ['art rock', 'brit funk', 'dance rock', 'mellow gold', 'new romantic', 'new wave', 'new wave pop', 'post-disco', 'soft rock', 'synthpop'], 'href': 'https://api.spotify.com/v1/artists/0L9xkvBPcEp1nrhDrodxc5', 'id': '0L9xkvBPcEp1nrhDrodxc5', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/8ef78093aa9d048ebf1cb9d60509315336dc1337', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/aadbe32cf208ee87fcaa6d0a51a8fe40a506ed7e', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/004a9ce002e25d42ee8cdef1aed62cfe91729731', 'width': 160}], 'name': 'Level 42', 'popularity': 60, 'type': 'artist', 'uri': 'spotify:artist:0L9xkvBPcEp1nrhDrodxc5'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0LbLWjaweRbO4FDKYlbfNt'}, 'followers': {'href': None, 'total': 944141}, 'genres': ['alternative rock', 'dance-punk', 'modern rock', 'rock'], 'href': 'https://api.spotify.com/v1/artists/0LbLWjaweRbO4FDKYlbfNt', 'id': '0LbLWjaweRbO4FDKYlbfNt', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/8e9a138bc3e9864cedd0a3d35e53e9ac8c23d0a5', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/091ef267c1477b5c1a71453c89bf135025fe8f45', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/e2e9fb2b3e56f2508350f9b5109d6d8a73f8e935', 'width': 160}], 'name': 'Kaiser Chiefs', 'popularity': 63, 'type': 'artist', 'uri': 'spotify:artist:0LbLWjaweRbO4FDKYlbfNt'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0LcJLqbBmaGUft1e9Mm8HV'}, 'followers': {'href': None, 'total': 4172054}, 'genres': ['europop', 'swedish pop'], 'href': 'https://api.spotify.com/v1/artists/0LcJLqbBmaGUft1e9Mm8HV', 'id': '0LcJLqbBmaGUft1e9Mm8HV', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/733e98edfdc11feea07914532603c080fa432159', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/0666d9d1b65b626e98c5273a4f44ff34951f8e1f', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/91b0c71fb753135bc083a11043797ce05168d00a', 'width': 160}], 'name': 'ABBA', 'popularity': 81, 'type': 'artist', 'uri': 'spotify:artist:0LcJLqbBmaGUft1e9Mm8HV'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0mkcYaXUbJUs5mJointuzB'}, 'followers': {'href': None, 'total': 116425}, 'genres': ['album rock', 'art rock', 'canterbury scene', 'jazz fusion', 'progressive rock', 'symphonic rock'], 'href': 'https://api.spotify.com/v1/artists/0mkcYaXUbJUs5mJointuzB', 'id': '0mkcYaXUbJUs5mJointuzB', 'images': [{'height': 691, 'url': 'https://i.scdn.co/image/40aecd496eff1df1d42a25d31859641e824517c0', 'width': 1000}, {'height': 442, 'url': 'https://i.scdn.co/image/515eef4ab96bc207f7b203332004fc76f5bd245b', 'width': 640}, {'height': 138, 'url': 'https://i.scdn.co/image/d0759c201f0e86481fb85377efda06f9eec20ad9', 'width': 200}, {'height': 44, 'url': 'https://i.scdn.co/image/9912b3975198e5fcb00fcf92a2756627a831ecdb', 'width': 64}], 'name': 'Rick Wakeman', 'popularity': 47, 'type': 'artist', 'uri': 'spotify:artist:0mkcYaXUbJUs5mJointuzB'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0MponVSpW81oLvJZ53vYZH'}, 'followers': {'href': None, 'total': 199498}, 'genres': ['brill building pop', 'classic girl group', 'classic soul', 'motown', 'rhythm and blues', 'soul', 'southern soul'], 'href': 'https://api.spotify.com/v1/artists/0MponVSpW81oLvJZ53vYZH', 'id': '0MponVSpW81oLvJZ53vYZH', 'images': [{'height': 1175, 'url': 'https://i.scdn.co/image/6c35aa5919baa5acc3700d65087963e5c5c784b8', 'width': 1000}, {'height': 752, 'url': 'https://i.scdn.co/image/191d689ef1230a37c0549470468a1e6eaadfcff9', 'width': 640}, {'height': 235, 'url': 'https://i.scdn.co/image/bc1d16d7241c9fbc298460b410f036409fb518d0', 'width': 200}, {'height': 75, 'url': 'https://i.scdn.co/image/a8e876f09e74cc61ced86a99349799a371fce69d', 'width': 64}], 'name': 'The Marvelettes', 'popularity': 57, 'type': 'artist', 'uri': 'spotify:artist:0MponVSpW81oLvJZ53vYZH'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0N5PyKJzS3M1XNlaCL7bbE'}, 'followers': {'href': None, 'total': 379781}, 'genres': ['brill building pop', 'classic soul', 'folk rock', 'funk', 'memphis soul', 'motown', 'rock-and-roll', 'soul', 'southern soul'], 'href': 'https://api.spotify.com/v1/artists/0N5PyKJzS3M1XNlaCL7bbE', 'id': '0N5PyKJzS3M1XNlaCL7bbE', 'images': [{'height': 1119, 'url': 'https://i.scdn.co/image/6938996289924918a6f9bb96af0bde4af969cb1c', 'width': 1000}, {'height': 716, 'url': 'https://i.scdn.co/image/9b5c587f17457d1d26d948e8b171e173b5c19c7d', 'width': 640}, {'height': 224, 'url': 'https://i.scdn.co/image/eed6b5c8e9bf119c1f8f0624c13fa2e1db38aeb8', 'width': 200}, {'height': 72, 'url': 'https://i.scdn.co/image/ffc80d044799b5fe5b641b2f98922e6b40f788d5', 'width': 64}], 'name': 'Wilson Pickett', 'popularity': 61, 'type': 'artist', 'uri': 'spotify:artist:0N5PyKJzS3M1XNlaCL7bbE'}]}
50
import sys
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "[RDS endpoint]"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

def main():

    try:
        conn = pymysql.connect(host, user=username, passwd=password, db=database, port=port, use_unicode=True, charset='utf8')
        cursor = conn.cursor()
    except:
        logging.error("could not connect to rds")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    cursor.execute("SELECT id FROM artists")
    artists = []

    for (id, ) in cursor.fetchall():
        artists.append(id)

    artist_batch = [artists[i: i+50] for i in range(0, len(artists), 50)]
    ## 배치사이즈를 50으로 제한
    ## artist_batch = [[artist아이디 50개], ... ,[artist아이디 50개]]

    artist_genres = []
    for i in artist_batch:

        ids = ','.join(i)
        URL = "https://api.spotify.com/v1/artists/?ids={}".format(ids)

        r = requests.get(URL, headers=headers)
        raw = json.loads(r.text)

        for artist in raw['artists']:
            for genre in artist['genres']:

                artist_genres.append(
                    {
                        'artist_id': artist['id'],
                        'genre': genre
                    }
                )

    for data in artist_genres:
        insert_row(cursor, data, 'pmstest.artist_genres')

    conn.commit()
    cursor.close()

    return None

def insert_row(cursor, data, table):
    placeholders = ', '.join(['%s'] * len(data)) ## %s,%s,%s,%s,%s ...
    columns = ', '.join(data.keys())
    key_placeholders = ', '.join(['{0}=%s'.format(k) for k in data.keys()])
    sql = "INSERT INTO %s ( %s ) VALUES ( %s ) ON DUPLICATE KEY UPDATE %s" % (table, columns, placeholders, key_placeholders)
    ## sql은 아래와 같은 형태가 될 것이다.
    ## INSERT INTO artists ( id, name, followers, popularity, url, image_url ) VALUES ( %s, %s, %s, %s, %s, %s )
    ## ON DUPLICATE KEY UPDATE id=%s, name=%s, followers=%s, popularity=%s, url=%s, image_url=%s
    cursor.execute(sql, list(data.values())*2)

def get_headers(client_id, client_secret):
    endpoint = "https://accounts.spotify.com/api/token"
    encoded = base64.b64encode("{}:{}".format(client_id, client_secret).encode('utf-8')).decode('ascii')
    headers = {"Authorization": "Basic {}".format(encoded)}
    payload = {"grant_type": "client_credentials"}
    r = requests.post(endpoint, data=payload, headers=headers)
    access_token = json.loads(r.text)['access_token']
    headers = {"Authorization": "Bearer {}".format(access_token)}
    return headers

if __name__=='__main__':
    main()

실행결과는 뭔가 print 되는 부분은 없고, 실행이 완료되고 해당 RDS 테이블에 가서 조회해보면 결과는 아래 그림과 같을것이다.

총 3246개의 데이터

image