Teniendo hojas con acordes (también tablaturas y otros pero no se trendrán en cuenta) para miles de canciones de rock nacional, voy a tratar de hacer un análisis usando estos datos y el poder de Python y sus librerías
Se tratará de responder preguntas como estas:
Se parte con la base de datos sqlite generada por el crawler de lacuerda para analizar todos los datos. Se utilizarán como librerías externas:
In [29]:
# Primera línea con todos los imports que se utilizaran
import collections
import operator
import re
import sqlite3
import unicodedata
import random
import requests
from pprint import pprint
In [ ]:
Lo primero que voy a hacer es generar mi dataset de canciones a utilizar. Para esto voy a tomar los textos que muestren los acordes de las canciones. Se utilizará siempre la mejor versión posible, una por canción. Solamente voy a utilizar artistas de rock nacional populares sacados de estas listas: https://es.wikipedia.org/wiki/Anexo:Las_100_canciones_m%C3%A1s_destacadas_del_rock_argentino_seg%C3%BAn_Rolling_Stone_y_MTV https://es.wikipedia.org/wiki/Anexo:Los_100_mejores_%C3%A1lbumes_del_rock_argentino_seg%C3%BAn_Rolling_Stone http://www.rollingstone.com.ar/1250916
In [2]:
# Scrapeando bandas de wikipedia
def get_textarea_content(url):
text = requests.get(url).text
match = re.search(r'<textarea .*?>(.*)</textarea>',
text,
re.MULTILINE|re.DOTALL)
assert match is not None, "no se encontró textarea"
return match.group(1)
print(get_textarea_content('https://es.wikipedia.org/w/index.php?title=Anexo:Las_100_canciones_m%C3%A1s_destacadas_del_rock_argentino_seg%C3%BAn_Rolling_Stone_y_MTV&action=edit§ion=1'))
In [3]:
# Busco los artistas de las 100 mejores canciones
text = get_textarea_content('https://es.wikipedia.org/w/index.php?title=Anexo:Las_100_canciones_m%C3%A1s_destacadas_del_rock_argentino_seg%C3%BAn_Rolling_Stone_y_MTV&action=edit§ion=1')
re_link = r'\[\[(?!\d+)(?:[^|\]]+\|)?([^\]]+)\]\]'
artistas = []
for line in text.splitlines():
links = re.findall(re_link, line)
artistas.extend(links[1:]) # El primer elemento es el título de la canción
artistas = set(artistas)
#pprint(artistas)
In [4]:
# Busco los artistas de los 100 mejores álbumes
text = get_textarea_content('https://es.wikipedia.org/w/index.php?title=Anexo:Los_100_mejores_%C3%A1lbumes_del_rock_argentino_seg%C3%BAn_Rolling_Stone&action=edit§ion=4')
artistas_albumes = set()
for line in text.splitlines():
links = re.findall(re_link, line)
if not links:
continue
artistas_albumes.add(links[0]) # El primer enlace linkea a la banda
#print(len(artistas_albumes), artistas_albumes)
artistas.update(artistas_albumes) # Añado al set global de artistas
In [5]:
print('Con esto tenemos una lista de', len(artistas), 'artistas para analizar')
Ya tenemos los nombres de los artistas. Ahora necesitamos para cada uno obtener el slug que le asignó lacuerda. Por ejemplo, si un artista es "Pescado Rabioso" el slug correcto es "pescado_rabioso". Generalmente tienen esta forma, aunque en algunos casos (ej: "Los auténticos decadentes" -> "autenticos") va a ser necesario cargarlo manualmente.
Voy a tratar de generar por cada artista un slug comun (uso el alfabeto ascii, convierto a minúscula y reemplazo espacios por guiones bajos). Si existe en la base de datos utilizo ese. Sino le doy la posibilidad al usuario de que lo introduzca manualmente.
In [6]:
# Obtengo el set de slugs de artistas que hay en la base de datos
conn = sqlite3.connect('lacuerda.db')
artistas_lacuerda = {row[0] for row in conn.execute('select slug from artista')}
print('Artistas en la DB:', len(artistas_lacuerda))
In [14]:
def elimina_tildes(s):
# Fuente: http://www.leccionespracticas.com/uncategorized/eliminar-tildes-con-python-solucionado
return ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn'))
def generar_slug(nombre):
return re.sub(r'\W+', '', elimina_tildes(nombre.lower().replace(' ', '_').replace('-', '_')))
In [15]:
slugs_a_probar = set(map(generar_slug, artistas))
print(len(slugs_a_probar), 'generados de', len(artistas), 'nombres de artistas')
slugs_correctos = artistas_lacuerda.intersection(slugs_a_probar)
print(len(slugs_correctos), 'de', len(slugs_a_probar), 'slugs encontrados automáticamente')
In [16]:
slugs = {}
for artista in artistas:
slug_a_probar = generar_slug(artista)
if slug_a_probar in artistas_lacuerda:
slugs[slug_a_probar] = artista # Asocio el slug al nombre de la banda
else:
# Entrada de datos manual
while True:
slug = input('Nombre para %s (dejar en blanco para ignorar): ' % artista)
if not slug:
break
if slug == 'quit':
raise KeyboardInterrupt() # No tengo ^C
if slug not in artistas_lacuerda:
print('El slug', slug, 'no pertenece a la base datos. Ingrese uno correcto')
else:
slugs[slug] = artista
break
pprint(slugs)
Una vez que tengo los slugs de los artistas a utilizar obtengo sus canciones y almaceno sus letras y acordes en una estructura de datos (en mi caso voy a usar una simple namedtuple).
In [25]:
Cancion = collections.namedtuple('Cancion', ('artista', 'slug', 'titulo', 'contenido'))
# Selecciono la version de acordes mas votada de cada cancion de un conjunto de artistas
query = """
select a.slug, c.slug, c.titulo, v.contenido
from version as v
join
(select
id_cancion, max(puntaje) as max_puntaje
from version
where formato="R"
group by id_cancion) as vj
on v.id_cancion=vj.id_cancion and v.puntaje=vj.max_puntaje
join cancion as c on v.id_cancion=c.rowid
join artista as a on c.slug_artista=a.slug
where formato="R" and a.slug in (%s)""" % ','.join('?'*len(slugs))
canciones = [Cancion(*row) for row in conn.execute(query, tuple(slugs))]
print(len(canciones), 'canciones a analizar')
In [28]:
print(next(filter(lambda c: c.slug=='flaca', canciones)).contenido)
In [48]:
print(random.choice(canciones).contenido)