In this Python and Tableau project I will scrape and visualize weekly streaming data from Spotify. I will use Python to scrape and append the data from Spotify into a CVS. Then I will load the CSV into Tableau and visualize the streaming trends.

Below I have embed the Python script from my GitHub repository:

Spotify Charts Scrapper

This scpript will scrape and append weekly streaming data from Spotify to a CSV. It's easy to adjust the script if you want to download daily streaming data.

The output CSV can easily be read by e.g. Tableau or Power BI.

Source: https://spotifycharts.com/regional

In [ ]:
import requests
import csv
import pandas as pd
import datetime
from os import path
import time
# ADD HEADERS TO THE FILE IF IT DOES NOT ALREADY EXIST
exist = path.exists("Spotify Charts_2.csv")
if exist == False:
    with open("Spotify Charts_2.csv","w",newline = '') as outFile:
        writer = csv.writer(outFile)
        writer.writerow(['Position','Track Name','Artist','Streams','URL','Week_Start','Week_End','Country','URL_embed'])
# START AND END DATE FOR FIRST WEEK (YEAR, MONTH, DAY)
week_start = datetime.date(2016, 12, 23)
week_end = datetime.date(2016, 12, 30)
# ENDING DATE (YEAR, MONTH, DAY)
end_date = datetime.date(2021, 2, 26)
delta = datetime.timedelta(days=7)
# COUNTRIES TO SCRAPE
countries = ['global','se','us','gb','ae','ar','at','au','be','bg','bo',\
             'br','ca','ch','cl','co','cr','cz','de','dk','do','ec','ee',\
             'eg','es','fi','fr','gr','gt','hk','hn','hu','id','ie','il',\
             'in','is','it','jp','kr','lt','lu','lv','ma','mx','my','ni',\
             'nl','no','nz','pa','pe','ph','pl','pt','py','ro','ru','sa',\
             'sg','sk','sv','th','tr','tw','ua','uy','un','za']
for country in countries:
    s_week = week_start
    e_week = week_end
    
    CN = country
    # IF YOU ADD A NEW COUNTRY PLEASE ADD IT'S FULL NAME HERE ALSO
    if country == 'global': CN = 'Global'
    elif country == 'se': CN = 'Sweden'
    elif country == 'us': CN = 'USA'
    elif country == 'gb': CN = 'United Kingdom'
    elif country == 'ae': CN = 'United Arab Emirates'
    elif country == 'ar': CN = 'Argentina'
    elif country == 'at': CN = 'Austria'
    elif country == 'au': CN = 'Australia'
    elif country == 'be': CN = 'Belgium'
    elif country == 'bg': CN = 'Bulgaria'
    elif country == 'bo': CN = 'Bolivia'
    elif country == 'br': CN = 'Brazil'
    elif country == 'ca': CN = 'Canada'
    elif country == 'ch': CN = 'Switzerland'
    elif country == 'cl': CN = 'Chile'
    elif country == 'co': CN = 'Colombia'
    elif country == 'cr': CN = 'Costa Rica'
    elif country == 'cz': CN = 'Czech Republic'
    elif country == 'de': CN = 'Germany'
    elif country == 'dk': CN = 'Denmark'
    elif country == 'do': CN = 'Dominican Republic'
    elif country == 'ec': CN = 'Ecuador'
    elif country == 'ee': CN = 'Estonia'
    elif country == 'eg': CN = 'Egypt'
    elif country == 'es': CN = 'Spain'
    elif country == 'fi': CN = 'Finland'
    elif country == 'fr': CN = 'France'
    elif country == 'gr': CN = 'Greece'
    elif country == 'gt': CN = 'Guatemala'
    elif country == 'hk': CN = 'Hong-Kong'
    elif country == 'hn': CN = 'Honduras'
    elif country == 'hu': CN = 'Hungary'
    elif country == 'id': CN = 'Indonesia'
    elif country == 'ie': CN = 'Ireland'
    elif country == 'il': CN = 'Israel'
    elif country == 'in': CN = 'India'
    elif country == 'is': CN = 'Iceland'
    elif country == 'it': CN = 'Italy'
    elif country == 'jp': CN = 'Japan'
    elif country == 'kr': CN = 'South Korea'
    elif country == 'lt': CN = 'Lithuania'
    elif country == 'lu': CN = 'Luxembourg'
    elif country == 'lv': CN = 'Latvia'
    elif country == 'ma': CN = 'Morocco'
    elif country == 'mx': CN = 'Mexico'
    elif country == 'my': CN = 'Malaysia'
    elif country == 'ni': CN = 'Nicaragua'
    elif country == 'nl': CN = 'Netherlands'
    elif country == 'no': CN = 'Norway'
    elif country == 'nz': CN = 'New Zealand'
    elif country == 'pa': CN = 'Panama'
    elif country == 'pe': CN = 'Peru'
    elif country == 'ph': CN = 'Philippines'
    elif country == 'pl': CN = 'Poland'
    elif country == 'pt': CN = 'Portugal'
    elif country == 'py': CN = 'Paraguay'
    elif country == 'ro': CN = 'Romania'
    elif country == 'ru': CN = 'Russia'
    elif country == 'sa': CN = 'Saudi Arabia'
    elif country == 'se': CN = 'Sweden'
    elif country == 'sg': CN = 'Singapore'
    elif country == 'sk': CN = 'Slovakia'
    elif country == 'sv': CN = 'El Salvador'
    elif country == 'th': CN = 'Thailand'
    elif country == 'tr': CN = 'Turkey'
    elif country == 'tw': CN = 'Taiwan'
    elif country == 'ua': CN = 'Ukraine'
    elif country == 'uy': CN = 'Uruguay'
    elif country == 'vn': CN = 'Vietnam'
    elif country == 'za': CN = 'South Africa'
        
    while e_week <= end_date:
        print(str(s_week)+"--"+str(e_week)+" ----> "+country)
        try:                        
            # REQUEST THE FILE FROM WEBSITE
            headers = {
                "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36"
            }
            res = requests.get("https://spotifycharts.com/regional/{}/weekly/{}--{}/download".format(country, str(s_week),str(e_week)))
            # SAVE THE CSV TO A TEMPORARY FILE FIRST
            with open("temp.csv","wb") as outFile:
                outFile.write(res.content)
            # NOW APPEND THE TEMPM FILE TO THE FINAL FILE
            df = pd.read_csv("temp.csv", skiprows=1)
            df['Week_Start'] = str(s_week)
            df['Week_End'] = str(e_week)
            df['Country'] = CN
            df['URL_embed'] = df['URL'].str.replace('https://open.spotify.com/track/','')
            df.to_csv('Spotify Charts_2.csv', mode='a', header=False, index=False)
            # SLEEP FOR 1 SECONDS, JUST TO AVOID GETTING BLOCKED
            time.sleep(1)            
        except:
            pass
        s_week += delta
        e_week += delta

Visit my profile on Tableau Public to see the Viz. Below I have attached a screenshot of the dashboard.