Python Forum
Getting TypeError: list indices must be integers or slices not str
Thread Rating:
  • 1 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Getting TypeError: list indices must be integers or slices not str
#1
I want to get the lyrics for each track returned from lastfm api. If i use the method song_lyric() below, that uses the musixmatch api, directy like:

song_lyric("(Another Song) All Over Again", "Justion Timberlake")
It works I get the lyric of the artist and track title informed in the method parameters:


Quote:name:::::(Another Song) All Over Againartsist::::Justin Timberlake
https://tracking.musixmatch.com/t1.0/m_h...mQOTsHKL6/

But if I use "song_lyric(name,artist)" in the code below its not working, in the firsts lyrics works but then when it reaches this same song "All Over Again" and it appears:

Traceback (most recent call last):
File "/Users/ozzy/PycharmProjects/semantic/semantic.py", line 240, in <module>
tracks[ID]['Lyric'] = song_lyric(title, tracks[ID]['Artist'])
File "/Users/ozzy/PycharmProjects/semantic/semantic.py", line 29, in song_lyric
body = json_obj["message"]["body"]["lyrics"]["lyrics_body"]
TypeError: list indices must be integers or slices, not str


Do you know how to solve this issue?

Code to get the lyrics of track based on artist name and title:


tracks = {}
#GET TRACKS FOR ALL THE ALBUMS
for i,v in albuns.items():
    artist = albuns[i]['Artist'].replace(" ","+")
    title = albuns[i]['Title'].replace(" ", "+")
    album = requests.get('http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key='+api_key+'&artist='+artist+'&album='+title)
    tree = ET.fromstring(album.content)
    for child in tree:
        for artist in child.findall('tracks'):
            for track in artist.findall('track'):
                name = track.find('name').text
                tracks[ID] = {}
                tracks[ID]['Title'] = name
                tracks[ID]['Artist'] = albuns[i]['Artist']
                tracks[ID]['Album'] = albuns[i]['Title']
                tracks[ID]['Lyric'] = song_lyric(title, tracks[ID]['Artist'])
                print("name:::::"+name + "artsist::::" +tracks[ID]['Artist'])
                song_lyric("(Another Song) All Over Again", "Justion Timberlake")
                song_lyric(name,artist)
                ID+=1
    print (ID)
Full working example:

import xml.etree.ElementTree as ET
import requests
import musicbrainzngs
import json
import urllib.request, urllib.error, urllib.parse
import socket

apikey_musixmatch = '0b4a363bbd71974c2634837d5b5d1d9a' #generated for the example
apiurl_musixmatch = 'http://api.musixmatch.com/ws/1.1/'

def song_lyric(song_name,artist_name):
    while True:
        querystring = apiurl_musixmatch + "matcher.lyrics.get?q_track=" + urllib.parse.quote(song_name) + "&q_artist=" + urllib.parse.quote(artist_name) +"&apikey=" + apikey_musixmatch + "&format=json&f_has_lyrics=1"
        #matcher.lyrics.get?q_track=sexy%20and%20i%20know%20it&q_artist=lmfao
        request = urllib.request.Request(querystring)
        #request.add_header("Authorization", "Bearer " + client_access_token)
        request.add_header("User-Agent", "curl/7.9.8 (i686-pc-linux-gnu) libcurl 7.9.8 (OpenSSL 0.9.6b) (ipv6 enabled)") #Must include user agent of some sort, otherwise 403 returned
        while True:
            try:
                response = urllib.request.urlopen(request, timeout=4) #timeout set to 4 seconds; automatically retries if times out
                raw = response.read()
            except socket.timeout:
                print("Timeout raised and caught")
                continue
            break


        json_obj = json.loads(raw.decode('utf-8'))
        body = json_obj["message"]["body"]["lyrics"]["lyrics_body"]
        copyright = json_obj["message"]["body"]["lyrics"]["lyrics_copyright"]

        tracking_url = json_obj["message"]["body"]["lyrics"]["html_tracking_url"]
        if(tracking_url != "" and body != ""):
            print(tracking_url)
            lyrics_tracking(tracking_url)
            return (body + "\n\n" +copyright)
        else:
            return "None"

def lyrics_tracking(tracking_url):
    while True:
        querystring = tracking_url
        request = urllib.request.Request(querystring)
        #request.add_header("Authorization", "Bearer " + client_access_token)
        request.add_header("User-Agent", "curl/7.9.8 (i686-pc-linux-gnu) libcurl 7.9.8 (OpenSSL 0.9.6b) (ipv6 enabled)") #Must include user agent of some sort, otherwise 403 returned
        try:
            response = urllib.request.urlopen(request, timeout=4) #timeout set to 4 seconds; automatically retries if times out
            raw = response.read()
        except socket.timeout:
            print("Timeout raised and caught")
            continue
        break
        print(raw)

ID = 1

api_key = "b088cbedecd40b35dd89e90f55227ac2" #This should be you LastFM API Key

bands = {}

#GET TOP ARTISTS
for i in range(2,5):
    artistslist = requests.get('http://ws.audioscrobbler.com/2.0/?method=geo.gettopartists&country=poland&page='+str(i)+'&api_key='+api_key)
    tree = ET.fromstring(artistslist.content)
    for child in tree:
        for artist in child.findall('artist'):
            if ID > 5: continue
            name = artist.find('name').text
            bands[ID] = {}
            bands[ID]['ID'] = ID
            bands[ID]['Name'] = name
            ID+=1
albuns = {}

#GET 15 TOP ALBUNS FROM ARTISTS
for i,v in bands.items():
    chosen = bands[i]['Name'].replace(" ", "+")
    topalbuns = requests.get('http://ws.audioscrobbler.com/2.0/?method=artist.gettopalbums&artist='+chosen+'&api_key='+api_key+'&limit=15')
    tree = ET.fromstring(topalbuns.content)
    for child in tree:
        for album in child:
            name = album.find('name').text
            albuns[ID] = {}
            albuns[ID]['ID'] = ID
            albuns[ID]['Artist'] = bands[i]['Name']
            albuns[ID]['ArtistID'] = bands[i]['ID']
            albuns[ID]['Title'] = name
            ID+=1
    print(ID)

print("TRACKS INFO")
tracks = {}
#GET TRACKS FOR ALL THE ALBUMS
for i,v in albuns.items():
    artist = albuns[i]['Artist'].replace(" ","+")
    title = albuns[i]['Title'].replace(" ", "+")
    album = requests.get('http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key='+api_key+'&artist='+artist+'&album='+title)
    tree = ET.fromstring(album.content)
    for child in tree:
        for artist in child.findall('tracks'):
            for track in artist.findall('track'):
                name = track.find('name').text
                tracks[ID] = {}
                tracks[ID]['Title'] = name
                tracks[ID]['Artist'] = albuns[i]['Artist']
                tracks[ID]['Album'] = albuns[i]['Title']
                tracks[ID]['AlbumID'] = albuns[i]['ID']
                tracks[ID]['Lyric'] = song_lyric(title, tracks[ID]['Artist'])
                print("name:::::"+name + "artsist::::" +tracks[ID]['Artist'])
                song_lyric("(Another Song) All Over Again", "Justion Timberlake")
                song_lyric(name,artist)
                ID+=1
    print (ID)
Reply
#2
Hi Ozzyk,

try to debug your code if you're using the PyCharm (as I suppose from your file path). It's easy and in this kind of problems it's always quickly leading to problem resolution.

I think you've a mistake on this line:
tracks[ID]['Lyric'] = song_lyric(title, tracks[ID]['Artist'])
You should call song_lyric function with a name of the song which would be:
tracks[ID]['Lyric'] = song_lyric(name, tracks[ID]['Artist'])
Reply
#3
Thanks for your answer. But that way it works also for firsts tracks but then it appears: ValueError: unknown url type: ''.

It seems that it works with:

if(tracking_url!= ""):
print(tracking_url)
lyrics_tracking(tracking_url)
return (body + "\n\n" +copyright)
else:
return "None"

Thanks!

Now it is appearing the same error with that solution above, " body = json_obj["message"]["body"]["lyrics"]["lyrics_body"]
TypeError: list indices must be integers or slices, not str".
Reply
#4
Yes because of this line:
song_lyric(name,artist)
"artist" is instance of Element object.

Delete this two lines from the for loop:
song_lyric("(Another Song) All Over Again", "Justion Timberlake")
song_lyric(name,artist)
You're not saving their result anyway.
Reply
#5
Thanks. I already had that lines commented, so should be other issue.
Reply
#6
For me it's working after two updates which I've described.

Does your for loop looks like this now?

# GET TRACKS FOR ALL THE ALBUMS
for i, v in albuns.items():
    artist = albuns[i]['Artist'].replace(" ", "+")
    title = albuns[i]['Title'].replace(" ", "+")
    album = requests.get(
        'http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=' + api_key + '&artist=' + artist + '&album=' + title)
    tree = ET.fromstring(album.content)
    for child in tree:
        for artist in child.findall('tracks'):
            for track in artist.findall('track'):
                name = track.find('name').text
                tracks[ID] = {}
                tracks[ID]['Title'] = name
                tracks[ID]['Artist'] = albuns[i]['Artist']
                tracks[ID]['Album'] = albuns[i]['Title']
                tracks[ID]['AlbumID'] = albuns[i]['ID']
                tracks[ID]['Lyric'] = song_lyric(name, tracks[ID]['Artist'])
                print("name:::::" + name + "artsist::::" + tracks[ID]['Artist'])
                ID += 1
Send the whole code again.
Reply
#7
Thanks again. Maybe you dont get the error because of the "ID > 2: continue", without this condition, with more tracks there will be some track that will give the error. For example if you just change the country to Germany like below and maintaining the "ID > 2: continue" the tracks returned are different and you can see that when it reachs some a specific track it appears the error.

  artistslist = requests.get('http://ws.audioscrobbler.com/2.0/?method=geo.gettopartists&country=germany&page='+str(i)+'&api_key='+api_key)
Reply
#8
Well, the error is appearing because if you're trying to get non-existing lyrics, you get response with another data structure. So it will fail here:

json_obj = json.loads(raw.decode('utf-8'))
body = json_obj["message"]["body"]["lyrics"]["lyrics_body"]
Try to put there a breaking point and debug it. You'll see it clearly.
Reply
#9
Thanks again. Do you know why this dont works "if(tracking_url!= "" or body != ""):"? It should not work because print(body) prints blank but I dont understand why.
Reply
#10
I'm sorry. I don't understand your question. Put here your actual code and point in it (with comment) where do you have problem.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  tuple indices must be integers or slices, not str cybertooth 16 11,589 Nov-02-2023, 01:20 PM
Last Post: brewer32
  No matter what I do I get back "List indices must be integers or slices, not list" Radical 4 1,175 Sep-24-2023, 05:03 AM
Last Post: deanhystad
  boto3 - Error - TypeError: string indices must be integers kpatil 7 1,269 Jun-09-2023, 06:56 PM
Last Post: kpatil
  Why do I have to repeat items in list slices in order to make this work? Pythonica 7 1,354 May-22-2023, 10:39 PM
Last Post: ICanIBB
  Response.json list indices must be integers or slices, not str [SOLVED] AlphaInc 4 6,424 Mar-24-2023, 08:34 AM
Last Post: fullytotal
Question How to append integers from file to list? Milan 8 1,454 Mar-11-2023, 10:59 PM
Last Post: DeaD_EyE
  "TypeError: string indices must be integers, not 'str'" while not using any indices bul1t 2 2,044 Feb-11-2023, 07:03 PM
Last Post: deanhystad
  Error "list indices must be integers or slices, not str" dee 2 1,470 Dec-30-2022, 05:38 PM
Last Post: dee
  TypeError: string indices must be integers JonWayn 12 3,406 Aug-31-2022, 03:29 PM
Last Post: deanhystad
  read a text file, find all integers, append to list oldtrafford 12 3,612 Aug-11-2022, 08:23 AM
Last Post: Pedroski55

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020