{ "cells": [ { "cell_type": "markdown", "id": "persistent-friendship", "metadata": {}, "source": [ "Spotify is one of the digital services that helped me to tide over the somber of Covid-19 lockdown. Therefore, I chose to explore its data in my first attempt to write code in python. After a bunch of trials and errors, I managed to extract songs and its features from spotify through the below codes in Jupyter lab notebook. Web reference to these codes are at the end." ] }, { "cell_type": "code", "execution_count": null, "id": "cooperative-little", "metadata": {}, "outputs": [], "source": [ "Part 1- The first step to extract data from spotify is to set up client cerdintials using spotify's API key" ] }, { "cell_type": "code", "execution_count": 29, "id": "eleven-smart", "metadata": {}, "outputs": [], "source": [ "# I found the API key from the spotify's developers website\n", "# https://developer.spotify.com/dashboard/login\n", "# PS- The client id expires after an hour of extraction\n", "\n", "import requests\n", "\n", "CLIENT_ID = 'add the client id from the website'\n", "CLIENT_SECRET = 'add the client secret from the website'\n", "\n", "AUTH_URL = 'https://accounts.spotify.com/api/token'\n", "\n", "auth_response = requests.post(AUTH_URL, {\n", " 'grant_type': 'client_credentials',\n", " 'client_id': CLIENT_ID,\n", " 'client_secret': CLIENT_SECRET,})\n", "\n", "# convert the response to JSON\n", "auth_response_data = auth_response.json()\n", "\n", "# save the access token\n", "access_token = auth_response_data['access_token']\n", "\n", "headers = {\n", " 'Authorization': 'Bearer {token}'.format(token=access_token)\n", "}\n", "\n", "# base URL of all Spotify API endpoints\n", "BASE_URL = 'https://api.spotify.com/v1/'" ] }, { "cell_type": "code", "execution_count": null, "id": "continuous-oliver", "metadata": {}, "outputs": [], "source": [ "Part 2- Below code allowed me to extract features of the song that topped the global charts " ] }, { "cell_type": "code", "execution_count": 33, "id": "stable-strain", "metadata": {}, "outputs": [], "source": [ "# Dakiti song was streamed the most globally in the first week of Jan 2021 \n", "# Refer- https://spotifycharts.com/regional/global/weekly/2021-01-01--2021-01-08\n", "track_id = '4MzXwWMhyBbmu6hOcLVD49?si=7d86fb3ca8fe410a' \n", "\n", "# actual GET request with proper header\n", "r = requests.get(BASE_URL + 'audio-features/' + track_id, headers=headers)\n", "\n", "# description of the result- https://developer.spotify.com/documentation/web-api/reference/#endpoint-get-audio-features" ] }, { "cell_type": "markdown", "id": "funny-runner", "metadata": {}, "source": [ "Part 3- Below code allowed me to extract the features of the songs from the albums of an artist. I chose one of the artists of Dakiti." ] }, { "cell_type": "code", "execution_count": 40, "id": "brutal-governor", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "EL ÚLTIMO TOUR DEL MUNDO --- 2020-11-27\n", "LAS QUE NO IBAN A SALIR --- 2020-05-10\n", "YHLQMDLG --- 2020-02-28\n", "OASIS --- 2019-06-28\n", "X 100PRE --- 2018-12-23\n" ] } ], "source": [ "for album in d['items']:\n", " print(album['name'], ' --- ', album['release_date'])" ] }, { "cell_type": "code", "execution_count": 50, "id": "under-philadelphia", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "EL ÚLTIMO TOUR DEL MUNDO\n", "LAS QUE NO IBAN A SALIR\n", "YHLQMDLG\n", "OASIS\n", "X 100PRE\n" ] } ], "source": [ "data = [] # will hold all track info\n", "albums = [] # to keep track of duplicates\n", "\n", "# loop over albums and get all tracks\n", "for album in d['items']:\n", " album_name = album['name']\n", " \n", "# here's a hacky way to skip over albums we've already grabbed\n", " trim_name = album_name.split('(')[0].strip()\n", "\n", " # this takes a few seconds so let's keep track of progress \n", " print(album_name)\n", " \n", " # pull all tracks from this album\n", " r = requests.get(BASE_URL + 'albums/' + album['id'] + '/tracks', \n", " headers=headers)\n", " tracks = r.json()['items']\n", " \n", " for track in tracks:\n", " # get audio features (key, liveness, danceability, ...)\n", " f = requests.get(BASE_URL + 'audio-features/' + track['id'], \n", " headers=headers)\n", " f = f.json()\n", " \n", " # combine with album info\n", " f.update({\n", " 'track_name': track['name'],\n", " 'album_name': album_name,\n", " 'short_album_name': trim_name,\n", " 'release_date': album['release_date'],\n", " 'album_id': album['id']\n", " })\n", " \n", " data.append(f)" ] }, { "cell_type": "code", "execution_count": 51, "id": "favorite-theology", "metadata": {}, "outputs": [], "source": [ "#create data frame of songs in the artist's spotify album\n", "\n", "import pandas as pd\n", "df = pd.DataFrame(data)" ] }, { "cell_type": "code", "execution_count": 71, "id": "immune-search", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | danceability | \n", "energy | \n", "key | \n", "loudness | \n", "mode | \n", "speechiness | \n", "acousticness | \n", "instrumentalness | \n", "liveness | \n", "valence | \n", "... | \n", "uri | \n", "track_href | \n", "analysis_url | \n", "duration_ms | \n", "time_signature | \n", "track_name | \n", "album_name | \n", "short_album_name | \n", "release_date | \n", "album_id | \n", "
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | \n", "0.716 | \n", "0.522 | \n", "5 | \n", "-6.834 | \n", "1 | \n", "0.0582 | \n", "0.1660 | \n", "0.000065 | \n", "0.1130 | \n", "0.224 | \n", "... | \n", "spotify:track:36DHxTW2xdr9GG15T9oK9L | \n", "https://api.spotify.com/v1/tracks/36DHxTW2xdr9... | \n", "https://api.spotify.com/v1/audio-analysis/36DH... | \n", "165199 | \n", "4 | \n", "EL MUNDO ES MÍO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "2020-11-27 | \n", "2d9BCZeAAhiZWPpbX9aPCW | \n", "
1 | \n", "0.811 | \n", "0.637 | \n", "10 | \n", "-4.835 | \n", "0 | \n", "0.0591 | \n", "0.2340 | \n", "0.000572 | \n", "0.1180 | \n", "0.471 | \n", "... | \n", "spotify:track:5RubKOuDoPn5Kj5TLVxSxY | \n", "https://api.spotify.com/v1/tracks/5RubKOuDoPn5... | \n", "https://api.spotify.com/v1/audio-analysis/5Rub... | \n", "130014 | \n", "4 | \n", "TE MUDASTE | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "2020-11-27 | \n", "2d9BCZeAAhiZWPpbX9aPCW | \n", "
2 | \n", "0.860 | \n", "0.725 | \n", "11 | \n", "-6.700 | \n", "1 | \n", "0.2490 | \n", "0.0464 | \n", "0.000091 | \n", "0.0994 | \n", "0.375 | \n", "... | \n", "spotify:track:0tjZv2hChdHZCW1zFXpy1J | \n", "https://api.spotify.com/v1/tracks/0tjZv2hChdHZ... | \n", "https://api.spotify.com/v1/audio-analysis/0tjZ... | \n", "162151 | \n", "4 | \n", "HOY COBRÉ | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "2020-11-27 | \n", "2d9BCZeAAhiZWPpbX9aPCW | \n", "
3 | \n", "0.762 | \n", "0.861 | \n", "4 | \n", "-4.075 | \n", "0 | \n", "0.0652 | \n", "0.1390 | \n", "0.000001 | \n", "0.0956 | \n", "0.588 | \n", "... | \n", "spotify:track:0Lsis3LB0XAK6XlTHXaJk2 | \n", "https://api.spotify.com/v1/tracks/0Lsis3LB0XAK... | \n", "https://api.spotify.com/v1/audio-analysis/0Lsi... | \n", "213609 | \n", "4 | \n", "MALDITA POBREZA | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "2020-11-27 | \n", "2d9BCZeAAhiZWPpbX9aPCW | \n", "
4 | \n", "0.856 | \n", "0.618 | \n", "7 | \n", "-4.892 | \n", "1 | \n", "0.2860 | \n", "0.0303 | \n", "0.000000 | \n", "0.0866 | \n", "0.391 | \n", "... | \n", "spotify:track:2XIc1pqjXV3Cr2BQUGNBck | \n", "https://api.spotify.com/v1/tracks/2XIc1pqjXV3C... | \n", "https://api.spotify.com/v1/audio-analysis/2XIc... | \n", "203201 | \n", "4 | \n", "LA NOCHE DE ANOCHE | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "2020-11-27 | \n", "2d9BCZeAAhiZWPpbX9aPCW | \n", "
5 rows × 23 columns
\n", "\n", " | danceability | \n", "energy | \n", "key | \n", "loudness | \n", "mode | \n", "speechiness | \n", "acousticness | \n", "instrumentalness | \n", "liveness | \n", "valence | \n", "... | \n", "uri | \n", "track_href | \n", "analysis_url | \n", "duration_ms | \n", "time_signature | \n", "track_name | \n", "album_name | \n", "short_album_name | \n", "release_date | \n", "album_id | \n", "
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | \n", "0.716 | \n", "0.522 | \n", "5 | \n", "-6.834 | \n", "1 | \n", "0.0582 | \n", "0.1660 | \n", "0.000065 | \n", "0.1130 | \n", "0.224 | \n", "... | \n", "spotify:track:36DHxTW2xdr9GG15T9oK9L | \n", "https://api.spotify.com/v1/tracks/36DHxTW2xdr9... | \n", "https://api.spotify.com/v1/audio-analysis/36DH... | \n", "165199 | \n", "4 | \n", "EL MUNDO ES MÍO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "2020-11-27 | \n", "2d9BCZeAAhiZWPpbX9aPCW | \n", "
1 | \n", "0.811 | \n", "0.637 | \n", "10 | \n", "-4.835 | \n", "0 | \n", "0.0591 | \n", "0.2340 | \n", "0.000572 | \n", "0.1180 | \n", "0.471 | \n", "... | \n", "spotify:track:5RubKOuDoPn5Kj5TLVxSxY | \n", "https://api.spotify.com/v1/tracks/5RubKOuDoPn5... | \n", "https://api.spotify.com/v1/audio-analysis/5Rub... | \n", "130014 | \n", "4 | \n", "TE MUDASTE | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "2020-11-27 | \n", "2d9BCZeAAhiZWPpbX9aPCW | \n", "
2 | \n", "0.860 | \n", "0.725 | \n", "11 | \n", "-6.700 | \n", "1 | \n", "0.2490 | \n", "0.0464 | \n", "0.000091 | \n", "0.0994 | \n", "0.375 | \n", "... | \n", "spotify:track:0tjZv2hChdHZCW1zFXpy1J | \n", "https://api.spotify.com/v1/tracks/0tjZv2hChdHZ... | \n", "https://api.spotify.com/v1/audio-analysis/0tjZ... | \n", "162151 | \n", "4 | \n", "HOY COBRÉ | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "2020-11-27 | \n", "2d9BCZeAAhiZWPpbX9aPCW | \n", "
3 | \n", "0.762 | \n", "0.861 | \n", "4 | \n", "-4.075 | \n", "0 | \n", "0.0652 | \n", "0.1390 | \n", "0.000001 | \n", "0.0956 | \n", "0.588 | \n", "... | \n", "spotify:track:0Lsis3LB0XAK6XlTHXaJk2 | \n", "https://api.spotify.com/v1/tracks/0Lsis3LB0XAK... | \n", "https://api.spotify.com/v1/audio-analysis/0Lsi... | \n", "213609 | \n", "4 | \n", "MALDITA POBREZA | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "2020-11-27 | \n", "2d9BCZeAAhiZWPpbX9aPCW | \n", "
4 | \n", "0.856 | \n", "0.618 | \n", "7 | \n", "-4.892 | \n", "1 | \n", "0.2860 | \n", "0.0303 | \n", "0.000000 | \n", "0.0866 | \n", "0.391 | \n", "... | \n", "spotify:track:2XIc1pqjXV3Cr2BQUGNBck | \n", "https://api.spotify.com/v1/tracks/2XIc1pqjXV3C... | \n", "https://api.spotify.com/v1/audio-analysis/2XIc... | \n", "203201 | \n", "4 | \n", "LA NOCHE DE ANOCHE | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "EL ÚLTIMO TOUR DEL MUNDO | \n", "2020-11-27 | \n", "2d9BCZeAAhiZWPpbX9aPCW | \n", "
... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
63 | \n", "0.787 | \n", "0.705 | \n", "0 | \n", "-7.582 | \n", "1 | \n", "0.0695 | \n", "0.1370 | \n", "0.000001 | \n", "0.1080 | \n", "0.499 | \n", "... | \n", "spotify:track:5mj8WVFcKdGA8p9HWGTSLc | \n", "https://api.spotify.com/v1/tracks/5mj8WVFcKdGA... | \n", "https://api.spotify.com/v1/audio-analysis/5mj8... | \n", "188654 | \n", "4 | \n", "Cuando Perriabas | \n", "X 100PRE | \n", "X 100PRE | \n", "2018-12-23 | \n", "7CjJb2mikwAWA1V6kewFBF | \n", "
64 | \n", "0.655 | \n", "0.725 | \n", "0 | \n", "-5.497 | \n", "1 | \n", "0.1880 | \n", "0.0327 | \n", "0.002640 | \n", "0.0611 | \n", "0.326 | \n", "... | \n", "spotify:track:1khmgu0pveJbkbpbkyvcQv | \n", "https://api.spotify.com/v1/tracks/1khmgu0pveJb... | \n", "https://api.spotify.com/v1/audio-analysis/1khm... | \n", "300579 | \n", "4 | \n", "La Romana | \n", "X 100PRE | \n", "X 100PRE | \n", "2018-12-23 | \n", "7CjJb2mikwAWA1V6kewFBF | \n", "
65 | \n", "0.767 | \n", "0.379 | \n", "0 | \n", "-10.348 | \n", "1 | \n", "0.0385 | \n", "0.6680 | \n", "0.000145 | \n", "0.2170 | \n", "0.252 | \n", "... | \n", "spotify:track:69ZaPBHhRMRDjRpW1ivnOU | \n", "https://api.spotify.com/v1/tracks/69ZaPBHhRMRD... | \n", "https://api.spotify.com/v1/audio-analysis/69Za... | \n", "230578 | \n", "4 | \n", "Como Antes | \n", "X 100PRE | \n", "X 100PRE | \n", "2018-12-23 | \n", "7CjJb2mikwAWA1V6kewFBF | \n", "
66 | \n", "0.600 | \n", "0.528 | \n", "0 | \n", "-6.554 | \n", "1 | \n", "0.0308 | \n", "0.2630 | \n", "0.000000 | \n", "0.5880 | \n", "0.142 | \n", "... | \n", "spotify:track:6pZHZndlo57dPCYnvlYFOE | \n", "https://api.spotify.com/v1/tracks/6pZHZndlo57d... | \n", "https://api.spotify.com/v1/audio-analysis/6pZH... | \n", "284853 | \n", "4 | \n", "RLNDT | \n", "X 100PRE | \n", "X 100PRE | \n", "2018-12-23 | \n", "7CjJb2mikwAWA1V6kewFBF | \n", "
67 | \n", "0.759 | \n", "0.536 | \n", "9 | \n", "-6.663 | \n", "0 | \n", "0.1730 | \n", "0.8210 | \n", "0.000005 | \n", "0.1070 | \n", "0.439 | \n", "... | \n", "spotify:track:2OWVCFTolecLiGZPquvWvT | \n", "https://api.spotify.com/v1/tracks/2OWVCFTolecL... | \n", "https://api.spotify.com/v1/audio-analysis/2OWV... | \n", "208080 | \n", "4 | \n", "Estamos Bien | \n", "X 100PRE | \n", "X 100PRE | \n", "2018-12-23 | \n", "7CjJb2mikwAWA1V6kewFBF | \n", "
68 rows × 23 columns
\n", "\n", " | danceability | \n", "energy | \n", "key | \n", "loudness | \n", "mode | \n", "speechiness | \n", "acousticness | \n", "instrumentalness | \n", "liveness | \n", "valence | \n", "... | \n", "uri | \n", "track_href | \n", "analysis_url | \n", "duration_ms | \n", "time_signature | \n", "track_name | \n", "album_name | \n", "short_album_name | \n", "release_date | \n", "album_id | \n", "
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | \n", "69.000000 | \n", "69.000000 | \n", "69.000000 | \n", "69.000000 | \n", "69.000000 | \n", "69.000000 | \n", "69.000000 | \n", "69.000000 | \n", "69.000000 | \n", "69.000000 | \n", "... | \n", "69 | \n", "69 | \n", "69 | \n", "69.000000 | \n", "69.0 | \n", "69 | \n", "69 | \n", "69 | \n", "69 | \n", "69 | \n", "
unique | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "... | \n", "69 | \n", "69 | \n", "69 | \n", "NaN | \n", "NaN | \n", "69 | \n", "5 | \n", "5 | \n", "5 | \n", "5 | \n", "
top | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "... | \n", "spotify:track:5RubKOuDoPn5Kj5TLVxSxY | \n", "https://api.spotify.com/v1/tracks/4UEuIEv9Wc3w... | \n", "https://api.spotify.com/v1/audio-analysis/53v2... | \n", "NaN | \n", "NaN | \n", "Ser Bichote | \n", "YHLQMDLG | \n", "YHLQMDLG | \n", "2020-02-28 | \n", "5lJqux7orBlA1QzyiBGti1 | \n", "
freq | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "... | \n", "1 | \n", "1 | \n", "1 | \n", "NaN | \n", "NaN | \n", "1 | \n", "20 | \n", "20 | \n", "20 | \n", "20 | \n", "
mean | \n", "0.744130 | \n", "0.663928 | \n", "4.840580 | \n", "-6.068261 | \n", "0.550725 | \n", "0.116468 | \n", "0.209574 | \n", "0.000281 | \n", "0.156283 | \n", "0.514128 | \n", "... | \n", "NaN | \n", "NaN | \n", "NaN | \n", "198843.391304 | \n", "4.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
std | \n", "0.106835 | \n", "0.122930 | \n", "3.632465 | \n", "1.713921 | \n", "0.501065 | \n", "0.093154 | \n", "0.210900 | \n", "0.001258 | \n", "0.112964 | \n", "0.240325 | \n", "... | \n", "NaN | \n", "NaN | \n", "NaN | \n", "39238.177695 | \n", "0.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
min | \n", "0.430000 | \n", "0.379000 | \n", "0.000000 | \n", "-10.805000 | \n", "0.000000 | \n", "0.028100 | \n", "0.010300 | \n", "0.000000 | \n", "0.061100 | \n", "0.050800 | \n", "... | \n", "NaN | \n", "NaN | \n", "NaN | \n", "130014.000000 | \n", "4.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
25% | \n", "0.683000 | \n", "0.580000 | \n", "1.000000 | \n", "-7.125000 | \n", "0.000000 | \n", "0.058200 | \n", "0.058900 | \n", "0.000000 | \n", "0.098000 | \n", "0.326000 | \n", "... | \n", "NaN | \n", "NaN | \n", "NaN | \n", "165199.000000 | \n", "4.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
50% | \n", "0.762000 | \n", "0.656000 | \n", "5.000000 | \n", "-5.749000 | \n", "1.000000 | \n", "0.077200 | \n", "0.139000 | \n", "0.000005 | \n", "0.108000 | \n", "0.514000 | \n", "... | \n", "NaN | \n", "NaN | \n", "NaN | \n", "196500.000000 | \n", "4.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
75% | \n", "0.826000 | \n", "0.764000 | \n", "7.000000 | \n", "-4.835000 | \n", "1.000000 | \n", "0.131000 | \n", "0.287000 | \n", "0.000065 | \n", "0.153000 | \n", "0.685000 | \n", "... | \n", "NaN | \n", "NaN | \n", "NaN | \n", "224512.000000 | \n", "4.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
max | \n", "0.900000 | \n", "0.881000 | \n", "11.000000 | \n", "-2.979000 | \n", "1.000000 | \n", "0.402000 | \n", "0.869000 | \n", "0.009910 | \n", "0.659000 | \n", "0.962000 | \n", "... | \n", "NaN | \n", "NaN | \n", "NaN | \n", "300579.000000 | \n", "4.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
11 rows × 23 columns
\n", "