I am trying to use range()
to fill in values in a list of dictionaries from a custom range.
I have this code:
import requests
import json
import time
test = []
for x in range(5000,5020):
page_url = f'https://api.jikan.moe/v4/anime/{x}/full'
response = requests.get(page_url)
json_data = json.loads(response.text)
test.append(json_data)
time.sleep(1)
anime_data = []
for dic in test:
anime = {
'call_id': range(5000,5020),
'title': dic.get('data',{}).get('title','title not found'),
'mal_id': dic.get('data',{}).get('mal_id', 'id not found'),
'url': dic.get('data',{}).get('url', 'url not found')
}
anime_data.append(anime)
The goal is to use numbers from 5000 to 5020 in sequence for the 'call_id'
key of each dict, so that the output would look like:
[{'call_id': 5000,
'title': 'title not found',
'mal_id': 'id not found',
'url': 'url not found'},
{'call_id': 5001,
'title': 'title not found',
'mal_id': 'id not found',
'url': 'url not found'},
{'call_id': 5002,
'title': 'Bari Bari Densetsu',
'mal_id': 5002,
'url': 'https://myanimelist.net/anime/5002/Bari_Bari_Densetsu'}]
The code did not work as intended. How can I get the desired result?
CodePudding user response:
Another approach to the problem: fundamentally, we would like to iterate over two lists in parallel - the raw API responses, and the numbers (from the range
) that we want to use in the anime
entries. So, the naive response is to use zip
, thus:
for call_id, dic in zip(range(5000, 5020), test):
anime = {
'call_id': call_id,
'title': dic.get('data',{}).get('title','title not found'),
'mal_id': dic.get('data',{}).get('mal_id', 'id not found'),
'url': dic.get('data',{}).get('url', 'url not found')
}
anime_data.append(anime)
However, this overlooks a more specific, built-in tool: the built-in enumerate
function. We just have to set the start
point appropriately; we don't need to worry about how many elements there are - it will just keep incrementing until we run out.
That looks like:
for call_id, dic in enumerate(test, 5000):
anime = {
'call_id': call_id,
'title': dic.get('data',{}).get('title','title not found'),
'mal_id': dic.get('data',{}).get('mal_id', 'id not found'),
'url': dic.get('data',{}).get('url', 'url not found')
}
anime_data.append(anime)
CodePudding user response:
Since there is already a loop to produce all the same 'call_id'
values that are in range(5000,5020)
- in order to make the API calls in the first place - a simple approach is to just create the final data directly in the first loop, instead of storing json_data
results and trying to process them in a later loop. That looks like:
anime_data = []
for x in range(5000,5020):
page_url = f'https://api.jikan.moe/v4/anime/{x}/full'
response = requests.get(page_url)
json_data = json.loads(response.text)
anime = {
'call_id': range(5000,5020),
'title': json_data.get('data',{}).get('title','title not found'),
'mal_id': json_data.get('data',{}).get('mal_id', 'id not found'),
'url': json_data.get('data',{}).get('url', 'url not found')
}
anime_data.append(anime)
time.sleep(1)
We can organize the logic better by using functions to split up the tasks performed each time through the loop, and by pre-computing the .get('data',{})
result:
def query_api(anime_id):
page_url = f'https://api.jikan.moe/v4/anime/{anime_id}/full'
response = requests.get(page_url)
return json.loads(response.text).get('data',{})
def make_anime_data(anime_id, raw_data):
return {
'call_id': anime_id,
'title': raw_data.get('title','title not found'),
'mal_id': raw_data.get('mal_id', 'id not found'),
'url': raw_data.get('url', 'url not found')
}
anime_data = []
for x in range(5000,5020):
raw_data = query_api(x)
anime_data.append(make_anime_data(x, raw_data))
time.sleep(1)