Hoy veremos algo interesante, vamos a jugar un rato con la API de Spotify ?
Para resumir un poco lo que vamos a tratar en este post: Intentaremos realizar un proceso ETL (Extract, transform and load) donde vamos a consumir información de la API que nos provee Spotify, luego vamos a realizar una limpieza de la info con la que nos responde la API para quedarnos únicamente con la información que queremos guardar y por último dichos datos vamos a ingestarlos en un cluster de Elasticsearch para poder verlos desde Kibana.
¿Que te parece la idea? Let’s do it ! ?
Antes de comenzar te recomiendo que leas el post de instalación del stack ELK y sigas los pasos para instalarlo. El post tambien se encuentra dentro del Blog.
Preparando el entorno
Vamos a crear una carpeta donde queremos realizar el proyecto, en mi caso lo llamé spotify-api y luego vamos a crear un entorno virtual de python llamado .spotify para instalar los paquetes necesarios. Luego vamos a activar el entorno virtual.
#Creando carpeta del Proyecto mkdir spotify-api #Ingresando a la carpeta cd spotify-api #Creando entorno virtual python3 -m venv .spotify #Activando entorno virtual source .spotify/bin/activate
Instalando librerías spotipy y elasticsearch
Si bien se podría acceder a los datos de Spotify a través de requests existe una librería de python llamado spotipy que nos facilitará muchísimo el trabajo. Si vamos a su documentación nos dice que es una pequeña librería de Python para la API de Spotify, les dejo el link en caso de que quieran inspeccionar un poco mas: docs spotipy
También vamos a instalar la librería de elasticsearch que nos va a permir interacturar con nuestra instalación de elastic y vamos a poder crear índices con sus mapping correspondientes y luego poder ingestar los datos que obtenemos desde la API de Spotify. docs elasticsearch
#Instalando liberías
pip install elasticsearch spotipy
#Verificando instalación
pip freeze
Como veremos en la siguiente imagen, las librerías se encuentran instaladas, junto con otras que se instalan automáticamente:

Genial, ya tenemos el entorno preparado y las librerías instaladas ? Ahora vamos a comenzar por configurar las credenciales de Spotify API.
Configurando Spotify API
Para comenzar vamos a ingresar a dashboard Spotify. Si no estas registrado, vas a tener que registrarte. Una vez que ya estés dentro del dashboard vamos a crear una aplicación, yo lo llamé jugando-con-spotify, y luego vamos a tener que configurar el redirect URIs, en mi caso puse la dirección del blog, puedes ingresar cualquier URL, incluso la de google te va a funcionar ?

Una vez que creemos la aplicación nos va a dar un CLIENT_ID y un CLIENT_SECRET que lo vamos a usar desde nuestra aplicación.
Una vez obtenido el CLIENT_ID y CLIENT_SECRET dentro de la carpeta del proyecto vamos a crear un archivo de configuración para almacenar ésta información y la información de conexión de Elasticsearch. En mi caso creé un archivo llamado secrets.ini. Puedes llamarlo como quisieras, siempre y cuando mantengas las extensión .ini (Existen otros archivos de configuración que no vamos a ver en este tutorial). El archivo al final se debería ver algo como esto:

Ahora si, vamos a crear un archivo llamado main.py donde vamos a comenzar a codificar.
Para conectarnos a Spotify lo que tenemos que hacer es crear un conector al que le vamos a pasar, el CLIENT_ID, CLIENT_SECRET, REDIRECT_URI que ya definimos anteriormente y el SCOPE. El scope es indicarle a Spotify qué permisos le vamos a pedir para que nos dé el usuario del que vamos a consumir la información. En nuestro caso vamos a usar el scope user-follow-read que son permisos suficientes para realizar lo que necesitamos en este tutorial. Si quieres saber un poco mas, puedes revisarlo en la documentación de scope de Spotify
El conector hacia Spotify lo vamos a crear gracias a un módulo SpotifyOAuth que nos facilita Spotipy:
sp = spotipy.Spotify(auth_manager=SpotifyOAuth( client_id = cfg['SPOTIFY']['SPOTIFY_CLIENT_ID'], client_secret = cfg['SPOTIFY']['SPOTIFY_CLIENT_SECRET'], redirect_uri = cfg['SPOTIFY']['SPOTIFY_REDIRECT_URI'], scope = cfg['SPOTIFY']['SPOTIFY_SCOPE'] ))
Bien, vamos bien ! Ahora que ya tenemos el conector con la API de Spotify vamos a consumir su información. En este tutorial vamos seleccionar un artísta desde la APP de spotify y obtendremos su ID luego le solicitaremos a Spotify a través a de la API que nos devuelva quienes son algunos artistas relacionados. Para el ejemplo vamos a elegir el artista PORTA, que es un cantante de RAP que me gusta mucho y vamos a ver qué artístas similares existen.
Para obtener el ARTIST_ID, abrimos la app de Spotify, buscamos el artista del cual queremos obtener artistas similares luego clickeamos en los …(tres puntitos) y damos share > copy link to artist.
Para eso Spotipy nos brinda el método artist_related_artists, al cual debemos pasarle el ARTIST_ID y nos devolverá 20 artístas que Spotify considera similares,
Para eso entonces vamos a crear una función en Python que le llamaremos _extract(artist_id) y la función va a retornar toda la información cruda con la que responde el API de Spotify, y luego crearemos nuestro punto inicial de Python y vamos a mostrar por consola, la información que nos retorna la API.
Al método _extract podemos pasarle la url completa o simplemente el código del artísta que sigue despues artists/ y antes de ? .

def _extract(artist_id):
return sp.artist_related_artists(artist_id)
if __name__ == '__main__':
now = datetime.now()
# Exctract
payload = _extract('3p7Bs02UWDt5ENoJeUGqaB')
print(payload)
Obteniendo datos desde la API de Spotify
¡ Es hora de probar nuestro código !
Desde una consola y posicionados en la carpeta del proyecto vamos a correrlo:
python3 main.py
Una vez que corramos, el programa, nos va a redireccionar a la URL que nosotros configuramos en secrets.ini y que ingresamos en la configuración dentro del dashboard de Spotify. La consola quedará esperando por la url, debemos copiar la url de la nueva pestaña que nos abrió en el navegador y pegarla en la consola

Una vez que ingresamos el código y presionamos <enter> la API de Spotify nos devolverá la respuesta, en mi caso fué el siguiente JSON
{'artists': [{'external_urls': {'spotify': 'https://open.spotify.com/artist/3m1an5fzquhCtk4UnhmLmc'}, 'followers': {'href': None, 'total': 292837}, 'genres': ['rap conciencia', 'spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/3m1an5fzquhCtk4UnhmLmc', 'id': '3m1an5fzquhCtk4UnhmLmc', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5eb4b496fdf281ee39c3aaf1b85', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab676161000051744b496fdf281ee39c3aaf1b85', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f1784b496fdf281ee39c3aaf1b85', 'width': 160}], 'name': 'El Chojin', 'popularity': 54, 'type': 'artist', 'uri': 'spotify:artist:3m1an5fzquhCtk4UnhmLmc'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/66ArjpKRgw8vYBf9yhktto'}, 'followers': {'href': None, 'total': 698389}, 'genres': ['latin hip hop', 'rap conciencia', 'spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/66ArjpKRgw8vYBf9yhktto', 'id': '66ArjpKRgw8vYBf9yhktto', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5ebfbea47204157562c808ef905', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab67616100005174fbea47204157562c808ef905', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f178fbea47204157562c808ef905', 'width': 160}], 'name': 'Nach', 'popularity': 62, 'type': 'artist', 'uri': 'spotify:artist:66ArjpKRgw8vYBf9yhktto'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/3uvTa6pDzj0T6EfMslXOCs'}, 'followers': {'href': None, 'total': 264053}, 'genres': ['latin viral pop'], 'href': 'https://api.spotify.com/v1/artists/3uvTa6pDzj0T6EfMslXOCs', 'id': '3uvTa6pDzj0T6EfMslXOCs', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5ebf500612f790d92a1701f1c11', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab67616100005174f500612f790d92a1701f1c11', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f178f500612f790d92a1701f1c11', 'width': 160}], 'name': 'Santaflow', 'popularity': 52, 'type': 'artist', 'uri': 'spotify:artist:3uvTa6pDzj0T6EfMslXOCs'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/7F9Bd5X4sxdwWRJVpbfMtb'}, 'followers': {'href': None, 'total': 195537}, 'genres': ['rap conciencia', 'spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/7F9Bd5X4sxdwWRJVpbfMtb', 'id': '7F9Bd5X4sxdwWRJVpbfMtb', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5ebe5c541dcee60e707096d7a2d', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab67616100005174e5c541dcee60e707096d7a2d', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f178e5c541dcee60e707096d7a2d', 'width': 160}], 'name': 'ZPU', 'popularity': 53, 'type': 'artist', 'uri': 'spotify:artist:7F9Bd5X4sxdwWRJVpbfMtb'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/451DVjaBuGYfvDfvG9MxaG'}, 'followers': {'href': None, 'total': 275892}, 'genres': ['rap conciencia', 'spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/451DVjaBuGYfvDfvG9MxaG', 'id': '451DVjaBuGYfvDfvG9MxaG', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5eb6b615e13073a7fe9cf9dad64', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab676161000051746b615e13073a7fe9cf9dad64', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f1786b615e13073a7fe9cf9dad64', 'width': 160}], 'name': 'Rapsusklei', 'popularity': 56, 'type': 'artist', 'uri': 'spotify:artist:451DVjaBuGYfvDfvG9MxaG'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/5Ef6JG1cW8s30S48REBgTa'}, 'followers': {'href': None, 'total': 69662}, 'genres': ['spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/5Ef6JG1cW8s30S48REBgTa', 'id': '5Ef6JG1cW8s30S48REBgTa', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab67616d0000b273ce99ceb719a1f44388371cc7', 'width': 640}, {'height': 300, 'url': 'https://i.scdn.co/image/ab67616d00001e02ce99ceb719a1f44388371cc7', 'width': 300}, {'height': 64, 'url': 'https://i.scdn.co/image/ab67616d00004851ce99ceb719a1f44388371cc7', 'width': 64}], 'name': 'Arma Blanca', 'popularity': 37, 'type': 'artist', 'uri': 'spotify:artist:5Ef6JG1cW8s30S48REBgTa'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/5GdP5J5VnVvhY0HzsYMcUK'}, 'followers': {'href': None, 'total': 181541}, 'genres': ['rap romantico'], 'href': 'https://api.spotify.com/v1/artists/5GdP5J5VnVvhY0HzsYMcUK', 'id': '5GdP5J5VnVvhY0HzsYMcUK', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5eb8fd39a970f8991a195999430', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab676161000051748fd39a970f8991a195999430', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f1788fd39a970f8991a195999430', 'width': 160}], 'name': 'Shé', 'popularity': 57, 'type': 'artist', 'uri': 'spotify:artist:5GdP5J5VnVvhY0HzsYMcUK'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/56n1NeXsTOOxjX3Z4lVMTJ'}, 'followers': {'href': None, 'total': 517542}, 'genres': ['rap underground espanol', 'spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/56n1NeXsTOOxjX3Z4lVMTJ', 'id': '56n1NeXsTOOxjX3Z4lVMTJ', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5eb3ab473e158510f75261428bf', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab676161000051743ab473e158510f75261428bf', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f1783ab473e158510f75261428bf', 'width': 160}], 'name': 'SFDK', 'popularity': 65, 'type': 'artist', 'uri': 'spotify:artist:56n1NeXsTOOxjX3Z4lVMTJ'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/5iQNy7hQGe1suvNOQz19Jz'}, 'followers': {'href': None, 'total': 136786}, 'genres': ['rap espanol', 'spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/5iQNy7hQGe1suvNOQz19Jz', 'id': '5iQNy7hQGe1suvNOQz19Jz', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5eb0fa32bebed39c29e7124c030', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab676161000051740fa32bebed39c29e7124c030', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f1780fa32bebed39c29e7124c030', 'width': 160}], 'name': 'AMBKOR', 'popularity': 57, 'type': 'artist', 'uri': 'spotify:artist:5iQNy7hQGe1suvNOQz19Jz'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/1DH9RJ0xBVje6gQmK3LWUY'}, 'followers': {'href': None, 'total': 423870}, 'genres': ['rap underground espanol', 'spanish hip hop', 'venezuelan hip hop'], 'href': 'https://api.spotify.com/v1/artists/1DH9RJ0xBVje6gQmK3LWUY', 'id': '1DH9RJ0xBVje6gQmK3LWUY', 'images': [{'height': 665, 'url': 'https://i.scdn.co/image/cf578e36ae2ac2fd006c4945c4e40f06029f3eda', 'width': 1000}, {'height': 426, 'url': 'https://i.scdn.co/image/0c3dd9c763d9b2bb3094b34fd09740d697bcebff', 'width': 640}, {'height': 133, 'url': 'https://i.scdn.co/image/2525224ea61479c27d5bf4b425770cb020769532', 'width': 200}, {'height': 43, 'url': 'https://i.scdn.co/image/1d8826b16be942c25898f6b276335268fc11746c', 'width': 64}], 'name': 'Violadores Del Verso', 'popularity': 58, 'type': 'artist', 'uri': 'spotify:artist:1DH9RJ0xBVje6gQmK3LWUY'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/6kSbf0Xe8Bdhitd3d6Jr2z'}, 'followers': {'href': None, 'total': 126189}, 'genres': ['lithuanian hip hop', 'spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/6kSbf0Xe8Bdhitd3d6Jr2z', 'id': '6kSbf0Xe8Bdhitd3d6Jr2z', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5ebd1c0df22f6c09ffa67c08bdb', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab67616100005174d1c0df22f6c09ffa67c08bdb', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f178d1c0df22f6c09ffa67c08bdb', 'width': 160}], 'name': 'Shotta', 'popularity': 53, 'type': 'artist', 'uri': 'spotify:artist:6kSbf0Xe8Bdhitd3d6Jr2z'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/5pIapcAHb6WV4fUjfQchMf'}, 'followers': {'href': None, 'total': 157778}, 'genres': ['spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/5pIapcAHb6WV4fUjfQchMf', 'id': '5pIapcAHb6WV4fUjfQchMf', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5eb25cf50df32a4463ca3948c2c', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab6761610000517425cf50df32a4463ca3948c2c', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f17825cf50df32a4463ca3948c2c', 'width': 160}], 'name': 'Sharif', 'popularity': 60, 'type': 'artist', 'uri': 'spotify:artist:5pIapcAHb6WV4fUjfQchMf'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/7GmXwGXJSsmWTkCyk5Twux'}, 'followers': {'href': None, 'total': 493130}, 'genres': ['spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/7GmXwGXJSsmWTkCyk5Twux', 'id': '7GmXwGXJSsmWTkCyk5Twux', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5ebcf528f5cea21607230fd23d9', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab67616100005174cf528f5cea21607230fd23d9', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f178cf528f5cea21607230fd23d9', 'width': 160}], 'name': 'Kase.O', 'popularity': 66, 'type': 'artist', 'uri': 'spotify:artist:7GmXwGXJSsmWTkCyk5Twux'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/1wGIhYkKWSq4yACtTkCkSX'}, 'followers': {'href': None, 'total': 3304758}, 'genres': ['rap conciencia', 'venezuelan hip hop'], 'href': 'https://api.spotify.com/v1/artists/1wGIhYkKWSq4yACtTkCkSX', 'id': '1wGIhYkKWSq4yACtTkCkSX', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5eba91405d63c939682e4efdcbc', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab67616100005174a91405d63c939682e4efdcbc', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f178a91405d63c939682e4efdcbc', 'width': 160}], 'name': 'Canserbero', 'popularity': 74, 'type': 'artist', 'uri': 'spotify:artist:1wGIhYkKWSq4yACtTkCkSX'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/18TsWSCZg6GvIcZ9XVhwJw'}, 'followers': {'href': None, 'total': 39236}, 'genres': [], 'href': 'https://api.spotify.com/v1/artists/18TsWSCZg6GvIcZ9XVhwJw', 'id': '18TsWSCZg6GvIcZ9XVhwJw', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5ebc97fcf1cea1e9bddc70fe1b9', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab67616100005174c97fcf1cea1e9bddc70fe1b9', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f178c97fcf1cea1e9bddc70fe1b9', 'width': 160}], 'name': 'Aitor', 'popularity': 43, 'type': 'artist', 'uri': 'spotify:artist:18TsWSCZg6GvIcZ9XVhwJw'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0zgFL90nGTrH2iOMD8Vysy'}, 'followers': {'href': None, 'total': 388803}, 'genres': ['guadalajara indie', 'latin hip hop', 'mexican hip hop', 'perreo'], 'href': 'https://api.spotify.com/v1/artists/0zgFL90nGTrH2iOMD8Vysy', 'id': '0zgFL90nGTrH2iOMD8Vysy', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5eb9dfa53788d727df9746725fc', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab676161000051749dfa53788d727df9746725fc', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f1789dfa53788d727df9746725fc', 'width': 160}], 'name': 'Sabino', 'popularity': 68, 'type': 'artist', 'uri': 'spotify:artist:0zgFL90nGTrH2iOMD8Vysy'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/224rbIjYbXaTI7lnP2ZMNJ'}, 'followers': {'href': None, 'total': 203085}, 'genres': ['rap underground espanol', 'spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/224rbIjYbXaTI7lnP2ZMNJ', 'id': '224rbIjYbXaTI7lnP2ZMNJ', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5eb9e61d7dcca262863575c5bc6', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab676161000051749e61d7dcca262863575c5bc6', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f1789e61d7dcca262863575c5bc6', 'width': 160}], 'name': 'ToteKing', 'popularity': 58, 'type': 'artist', 'uri': 'spotify:artist:224rbIjYbXaTI7lnP2ZMNJ'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/6qqvdLm9ZVjxCgHxGcL5ZW'}, 'followers': {'href': None, 'total': 236342}, 'genres': ['latin viral rap'], 'href': 'https://api.spotify.com/v1/artists/6qqvdLm9ZVjxCgHxGcL5ZW', 'id': '6qqvdLm9ZVjxCgHxGcL5ZW', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5ebffa164cd9227e301365b6b2b', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab67616100005174ffa164cd9227e301365b6b2b', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f178ffa164cd9227e301365b6b2b', 'width': 160}], 'name': 'Doblecero', 'popularity': 54, 'type': 'artist', 'uri': 'spotify:artist:6qqvdLm9ZVjxCgHxGcL5ZW'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/5NNlkZBrBpOJ7C11JwVxIj'}, 'followers': {'href': None, 'total': 969754}, 'genres': ['emo mexicano', 'mexican pop punk', 'mexican rock', 'punk rock mexicano'], 'href': 'https://api.spotify.com/v1/artists/5NNlkZBrBpOJ7C11JwVxIj', 'id': '5NNlkZBrBpOJ7C11JwVxIj', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5ebb567ff9dc4dc5f2dc1201daa', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab67616100005174b567ff9dc4dc5f2dc1201daa', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f178b567ff9dc4dc5f2dc1201daa', 'width': 160}], 'name': 'PXNDX', 'popularity': 70, 'type': 'artist', 'uri': 'spotify:artist:5NNlkZBrBpOJ7C11JwVxIj'}, {'external_urls': {'spotify': 'https://open.spotify.com/artist/0xCQDfPyQwk4sFpOfYQRtH'}, 'followers': {'href': None, 'total': 18367}, 'genres': ['spanish hip hop'], 'href': 'https://api.spotify.com/v1/artists/0xCQDfPyQwk4sFpOfYQRtH', 'id': '0xCQDfPyQwk4sFpOfYQRtH', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6761610000e5eb043352cac176297fdd92a165', 'width': 640}, {'height': 320, 'url': 'https://i.scdn.co/image/ab67616100005174043352cac176297fdd92a165', 'width': 320}, {'height': 160, 'url': 'https://i.scdn.co/image/ab6761610000f178043352cac176297fdd92a165', 'width': 160}], 'name': 'Shinoflow', 'popularity': 34, 'type': 'artist', 'uri': 'spotify:artist:0xCQDfPyQwk4sFpOfYQRtH' }] }
Transformando la información obtenida desde la API
Genial, ya pudimos obtener información de la API de Spotify ?
Ahora, de toda la info que nos devolvió Spotify vamos a ordenar un poco, limpiarlo para luego ingestar en elasticsearch. Vamos a hacer algo super sencillo, como separar en un JSON solamente la información que necesitamos.
Creamos un objeto data, y luego vamos recorriendo el JSON que nos retornó la API, y al objeto data vamos a cargar cierta información.
Para eso vamos a crear una nueva función que llamaremos _transform()
def _transform(payload, current_date): data = [] for artist in payload['artists']: data.append( { "artist_name": artist['name'], "id": artist['id'], "popularity": artist['popularity'], "followers_number": artist['followers']['total'], "href_url": artist['href'], "uri": artist['uri'], "date_load": (current_date.strftime("%d/%m/%Y %H:%M:%S")) } ) json_object = json.dumps(data, indent=4) return json_object
Ingestando información en Elasticsearch
Llegó la hora de cargar toda la información a Elasticsearch ⏲️? ?
Para ello vamos a crear una función llamada _load(). Pero no tan rápido amigo! Primero vamos a crear 2 funciones:
- _create_index_elastic(): Crea la conexión a elasticseach.
- _create_index_elastic(): En este caso vamos a crear el índice indicando todos lo campos que vamos a guardar en el índice. (Más adelante haré un post sobre esto, pero por hoy no viene al caso)
def _create_conection_elastic(host='localhost', port=9200): es = Elasticsearch([ {'host': cfg['ELASTIC_SETTING']['HOST'], 'port': cfg['ELASTIC_SETTING']['PORT']} ]) return es def _create_index_elastic(): es = _create_conection_elastic() body = { 'settings' : { 'number_of_shards': 3, 'number_of_replicas': 1 }, 'mappings': { 'properties': { 'artist_name': {'type': 'text'}, 'id': {'type': 'text'}, 'popularity': {'type': 'integer'}, 'followers_number': {'type': 'text'}, 'href_url': {'type': 'text'}, 'uri': {'type': 'text'}, 'date_load': {'format': 'dd/MM/yyyy HH:mm:ss', 'type': 'date'}, } } } try: print(". . . Creating artists-related-spotify index ...") es.indices.create(index='artists-related-spotify', body=body) except RequestError as es1: print('. . . artists-related-spotify index already exists') return es
Ahora sí, creamos la función _load() y tambíen el main del archivo python para llamar a todas las funciones y que nuestro código funcione a la perfección ?
def _load(data): es = _create_conection_elastic() ci = _create_index_elastic() print(". . . Loading json data in elasticsearch") try: for item in json.loads(data): es.index(index='artists-related-spotify', body=item) except: print("Algo salió Mal :-( ") return None print("Data inserted correctly ...") if __name__ == '__main__': now = datetime.now() # Extract payload = _extract('3p7Bs02UWDt5ENoJeUGqaB') # Transform json_data = _transform(payload, now) # Load _load(json_data)
¡ Llegó la hora de probar todo ! ?
Vamos a ejecutar nuestro código. Dentro de la carpeta del proyecto escribimos el siguiente comando:
python3 main.py
he aquí el resultado:

Aparentemente salió todo como esperábamos ?
Vamos a checar si se creó el índice en elastic y tendría que tener un total de 20 documentos, ya que son 20 los artístas que nos retorna el API de Spotify. En mi caso voy a ingresar a Kibana, en mi localhost ya que lo tengo configurado ahí localhost:5601. En el menú de kibana nos dirigimos a Stack Managment y seleccionamos Index Managment y deberíamos ver todos los índices que tenemos y entre ellos el índice que creamos artists-related-spotify, y efectivamente lo vemos:

Y además también vemos que se encuentran los 20 documentos con los artistas similares que nos retornó Spotify API ?
Para finalizar vamos a crear un Index pattern, desde la misma pantalla de la imagen anterior. En la sección de Kibana seleccionamos Index Pattern y clickeamos en create Index Pattern, luego en el nombre colocamos el nombre del índice que creamos artists-related-spotify y presionamos en el botón next step.

Luego nos pedirá que seleccionemos un campo de fecha para realizar filtros por medio de dicho campo, seleccionamos el único campo que tenemos de tipo fecha date_load y presionamos sobre create index pattern, y listo.
Ahora si vamos al menú de la sección Analytics > Discover, podemos visualizar mucho mejor toda la información que ingestamos. Mas adelante en un nuevo post, crearemos un tablero desde kibana para visualizar todo de forma mucho mas gráfica.


Y eso es todo, hemos aprendido a hacer un sencillo proceso ETL con Python ?
Les dejo el codigo completo en mi repositorio: Repo spotify-api
Espero que te haya hecho de mucha ayuda, cualquier consulta y/o corrección es bienvenida y nos vemos en un siguiente post ?