tacosdedatos

Isaac Arroyo
Isaac Arroyo

Posted on

Spotipy: Extraer características de canciones

Nota: Doy una advertencia ⚠️ de que no soy programador como profesión, por lo que los términos que usaré no serán específicos.

Repaso rapidín

Spotipy es una librería de Python que nos facilita las peticiones y el manejo de la API de Spotify. Para poder usar la librería (y por ende la API), además de instalarla, hay que registrarnos como Developer y crear una App, para que de esa manera tengamos nuestras claves (Client ID y Client Secret). Para mayores detalles, te invito a leer el primer artículo de esta serie:

Introducción informal

En este tutorial vamos a indagar un poco más en el código, como funciona cada parte, explicar las funciones que usaremos así como entender como son los datos que vamos a recibir y como vamos a exportarlos como un archivo csv.

Continuando dónde lo dejamos y lo que teníamos pendiente, vamos a ir por partes.

Entrar a Spotify

A estas líneas de código les llamo Pedir permiso. Lo que estamos haciendo primero es importar la librería de Spotipy asi como nuestro manager de credenciales o claves.

import spotipy
from spotipy.oauth2 import SpotifyClientCredentials # Manager de credenciales
Enter fullscreen mode Exit fullscreen mode

Seguidamente, a ese manager le damos nuestro Client ID y Client Secret

clientID = 'CLIENT_ID'
clientSecret = 'CLIENT_SECRET'

client_credential_manager = SpotifyClientCredentials(client_id=clientID, client_secret=clientSecret)
Enter fullscreen mode Exit fullscreen mode

Con client_credential_manager ya podemos "entrar a Spotify", es decir, ya tenemos los permisos para pedir datos

sp = spotipy.Spotify(client_credentials_manager=client_credential_manager)
Enter fullscreen mode Exit fullscreen mode

Anatomía de los datos

Vamos a entender que es lo que obtenemos cuando pedimos las canciones de un album. Seguiremos usando el URI del album ✨ "Harry's House" por Harry Styles ✨

La función a usar es album_tracks(), donde el parámetro a dar es el URI del album la respuesta que obtenemos es un diccionario de características del album

uri_harrys_house = 'spotify:album:5r36AJ6VOJtp00oxSkBZ5h'
dict_harrys_house = sp.album_tracks(uri_harrys_house)
print(dict_harrys_house.keys())

# OUTPUT
# dict_keys(['href', 'items', 'limit', 'next', 'offset', 'previous', 'total'])
Enter fullscreen mode Exit fullscreen mode

A nosotros nos interesa la llave o key llamada 'limit', el item o elemento de esa llave es una lista que contiene las canciones:

list_harrys_house_canciones = dict_harrys_house['items']
print(f"El album tiene {len(list_harrys_house_canciones)} canciones")

# OUTPUT
# El album tiene 13 canciones
Enter fullscreen mode Exit fullscreen mode

Cada elemento de esa lista es una canción cuya información esta almacenada en un diccionario:

dict_primera_cancion = list_harrys_house_canciones[0]
print(dict_primera_cancion.keys())

# OUTPUT
# dict_keys(['artists', 'available_markets', 'disc_number', 'duration_ms', 'explicit', 'external_urls', 'href', 'id', 'is_local', 'name', 'preview_url', 'track_number', 'type', 'uri'])
Enter fullscreen mode Exit fullscreen mode

Las llaves que nos interesan para crear nuestro conjunto de datos son 'name', 'uri' y 'duration_ms'. Para ello vamos a crear una lista y almacenar esa información, para ello tendremos que iterar sobre la lista de canciones:

list_names_songs = []
list_uri_songs = []
list_duration_ms = []

for cancion in list_harrys_house_canciones:
    list_names_songs.append(cancion['name'])
    list_uri_songs.append(cancion['uri'])
    list_duration_ms.append(cancion['duration_ms'])
Enter fullscreen mode Exit fullscreen mode

Extraer las audio features

Con una lista de URIs, extraer las audio features es mucho más fácil.

La función que usaremos es audio_features() la cual toma como parámetros la URI como una string (str) o una lista de URIs, como lo que tenemos nosotros. Lo que nos va a regresar es una lista... de diccionarios.

list_audio_features_canciones = sp.audio_features(list_uri_songs)
Enter fullscreen mode Exit fullscreen mode

Nota importante: Existe un límite de peticiones y es 100, es decir, el número máximo de URIs en una lista es de 100.

¿Qué llaves tienen los diccionarios que son parte de la list_audio_features_canciones?

dict_primer_elemento_list_audio_features = list_audio_features_canciones[0]
print(dict_primer_elemento_list_audio_features.keys())

# OUTPUT
# dict_keys(['danceability', 'energy', 'key', 'loudness', 'mode', 'speechiness', 'acousticness', 'instrumentalness', 'liveness', 'valence', 'tempo', 'type', 'id', 'uri', 'track_href', 'analysis_url', 'duration_ms', 'time_signature'])
Enter fullscreen mode Exit fullscreen mode

LAS AUDIO FEATURES, pero...

¿Que son las audio features?

Son propiedades que Spotify le da a las canciones, la cuales pueden ser muy técnicas (como el promedio de decibeles que emite la canción) así como un poco más elaboradas (como la energía de la canción). La lista es la siguiente:

Nombre Descripción Rango y tipo de dato
acousticness Es el nivel de confianza de que la canción sea acústica va de 0 a 1 (float)
danceability Indica que tan bailable es una canción basándose en diferentes elementos musicales como tempo, ritmo, beat, entre otros. va de 0 a 1 (float)
duration_ms El tiempo de duración de la canción en milisegundos. float
energy Valores altos de energía representan canciones rápidas, activas y ruidosas, de lo contrario la energía es baja. Toma en cuenta aspectos como rango dinámico, timbre, volumen percibido, entre otros. va de 0 a 1 (float)
instrumentalness Predice si la canción no contiene vocales. Entre más instrumental sea la canción, más alto el valor de este atributo. Canciones del género de rap tienen un bajo valor. va de 0 a 1 (float)
liveness Este valor indica la presencia de audiencia. Entre más audiencia detecta, más alto su valor y mayor probabilidad es de que la canción haya sido en vivo va de 0 a 1 (float)
loudness La presencia de riudo en decibeles (dB), la amplitud de las ondas de la canción. Este valor es el promedio de la canción. va de -60 a 0] (float)
speechiness Detecta la presencia de palabras. Muy altos niveles indican audiolibros, podcasts, entre otros; altos niveles pueden ser canciones del género rap, valores bajos indican poco aporte de palabras en la canción. va de 0 a 1 (float)
tempo Los Beats Per Minute (BPM), la velocidad o el paso de una canción. (float)
valence Describe la positividad de la canción. Valores altos indican mayor positividad (alegría, euforia, ánimos) y valores bajos indican más negatividad (tristeza, depresión, enojo). va de 0 a 1 (float)
key Clasifica el pitch o las notas de la canción. Canciones con bajo pitch suenan más graves, mientras que con alto pitch suenan más agudos. Cuando no se conoce el valor se marca -1. va de -1 a 11 (categoria)
time_signature La notación convencional que indica cuantos beats hay en cada bar. Se escriben únicamente los numeradores, ya que el denominador es 4. Por ejemplo, "4/4" o "7/4" va de 1 a 7 (categoria)
mode Indica la modalidad (mayor o menor) de una canción, el tipo de escala del que se deriva su contenido melódico. La mayor se representa con 1 y la menor con 0. 0 y 1 (categoria)

Crear un data frame

Ya que sabemos cuenta que ahora que son las audio features y como están guardadas, es tiempo de llevar los valores de la lista de diccionarios a un pandas.DataFrame. Para ello ejecutaremos las siguientes líneas de código:

1 - Vamos a crear un diccionario de listas vacías. Donde cada llave es un audio feature.

dict_canciones_caracteristicas = dict(
    # Bueno, name no es lista vacia
    # pero las demás si
    name = list_names_songs,
    danceability = [],
    energy = [],
    key = [],
    loudness = [],
    mode = [],
    speechiness = [],
    acousticness = [],
    instrumentalness = [],
    liveness = [],
    valence = [],
    tempo = [],
    duration_ms = []
)
Enter fullscreen mode Exit fullscreen mode

2 - Vamos a iterar a través de cada elemento (será un diccionario) de list_audio_features_canciones. En esa iteración, vamos a iterar por las llaves de cada elemento y encontrar si alguna de ellas también está en nuestro diccionario (semi) vacío dict_canciones_caracteristicas. Si la llave está, entonces se guarda ese audio feature de esa canción.

# Primera iteraciòn: a través de los elementos de la lista de audio features
for dict_audio_features_cancion in list_audio_features_canciones:
    # Segunda iteración: a través de las llaves del diccionario
    for llave in dict_audio_features_cancion:
        # Revisamos si una de sus llaves esta en dict_canciones_caracteristicas
        if llave in list(dict_canciones_caracteristicas.keys()):
            # Si está, se guarda el audio feature en la llave correcta
            dict_canciones_caracteristicas[llave].append(dict_audio_features_cancion[llave])
Enter fullscreen mode Exit fullscreen mode

Con el diccionario lleno, es tiempo de volverlo un pandas.DataFrame:

df = pd.DataFrame(dict_canciones_caracteristicas)
Enter fullscreen mode Exit fullscreen mode

Y terminamos al exportarlo como un archivo csv:

df.to_csv("./harrys_house_spotify_audio_features.csv", index=False)
Enter fullscreen mode Exit fullscreen mode

Conclusión y palabras finales

En este no tan corto tutorial, intenté ser lo más claro para que puedan extraer las características de las canciones del album de su artista favorito. Este proceso se puede repetir para playlist personales así como para playlist públicas.

Espero haber sido de ayuda. En los siguiente tutoriales veremos que hacer cuando son más de 100 canciones.

Para cualquier duda esta la sección de comentarios o mis DM en twitter (@unisaacarroyov) 🤓

Repositorio (jupyter notebook)

Da click aquí para poder ver la jupyter notebook de todo este proceso.

Discussion (2)

Collapse
carlospregunton profile image
Carlos Preguntón

más de 100 canciones ?

Collapse
unisaacarroyov profile image
Isaac Arroyo Author

Sip @carlospregunton , la API de Spotify solo te deja extraer 100 canciones por petición. Por lo que cuando son más, tienes que ir segmentando de 100 en 100 hasta el final.