Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 'list' object has no attribute 'keys' when trying to write a row in CSV file

I am trying to write a new row into a CSV file and I can't because I get an error in Python Shell.

Below is the code I am using (I am reading JSON from API and want to put data into CSV file)

# import urllib library
from urllib.request import Request, urlopen
c=1
# import json
import json
# store the URL in url as 
# parameter for urlopen
import pandas as pd
import csv
headerList = ['name','id','order','height','weight','speed','special_defense','special_attack','defense','attack','hp']
  
# open CSV file and assign header
with open("pokemon_stats.csv", 'w') as file:
    dw = csv.DictWriter(file, delimiter=',', 
                        fieldnames=headerList)
    dw.writeheader()
  
# display csv file
fileContent = pd.read_csv("pokemon_stats.csv")
for r in range(1,3):
    req = Request('https://pokeapi.co/api/v2/pokemon/'+str(r)+'/', headers={'User-Agent': 'Chrome/32.0.1667.0'})
  
# store the response of URL
    response = urlopen(req)

# storing the JSON response 
# from url in data
    data_json = json.loads(response.read())

#print(data_json)

    for key, value in data_json.items():
        if key=='name':
            name=value
        elif key=='id':
            id=value
        elif key=='order':
            order=value
        elif key=='height':
            height=value
        elif key=='weight':
            weight=value
        elif key == 'stats':
            for sub in data_json['stats']:
                for i in sub:
                    if i=='base_stat':
                        base_stat=sub[i]
                    if i=='stat':
                        for j in sub[i]:
                            if j=='name':
                                stat_name=sub[i][j]
                                if stat_name=='hp':
                                    hp=base_stat
                                elif stat_name=='attack':
                                    attack=base_stat
                                elif stat_name=='defense':
                                    defense=base_stat
                                elif stat_name=='special-attack':
                                    special_attack=base_stat
                                elif stat_name=='special-defense':
                                    special_defense=base_stat
                                elif stat_name=='speed':
                                    speed=base_stat
    data = [name,id,order,height,weight,speed,special_defense,special_attack,defense,attack,hp]
    dw.writerow(data)

After I try the execution of this code I get an error as it follows:

Traceback (most recent call last):
  File "C:/Users/sbelcic/Desktop/NANOBIT_API.py", line 117, in <module>
    dw.writerow(data)
  File "C:\Users\sbelcic\AppData\Local\Programs\Python\Python37\lib\csv.py", line 155, in writerow
    return self.writer.writerow(self._dict_to_list(rowdict))
  File "C:\Users\sbelcic\AppData\Local\Programs\Python\Python37\lib\csv.py", line 148, in _dict_to_list
    wrong_fields = rowdict.keys() - self.fieldnames
AttributeError: 'list' object has no attribute 'keys'*

Can somebody pls help and tell me what I am doing wrong.

I don't have working experience of manipulating JSON response with Python so any comments are welcome. If someone sees a better way to do this he is welcome to share.

like image 891
GodDamnLawyer Avatar asked Jan 31 '26 02:01

GodDamnLawyer


2 Answers

Since dw is a DictionaryWriter, data needs to be a dictionary (currently it's a list) as seen in the documentation.

Convert data to a dictionary with your headers

data = [name,id,order,height,weight,speed,special_defense,special_attack,defense,attack,hp]
data = dict(zip(headerList, data))
dw.writerow(data)
like image 176
Tobi208 Avatar answered Feb 02 '26 18:02

Tobi208


Check the example for using the DictWriter. You need to pass a dictionary to writerow instead of a list, so your last line should be

data =['name':name,'id': id,'order':order,'height': height,'weight':weight,'speed':speed,'special_defense':special_defense,'special_attack':special_attack,'defense':defense,'attack':attack,'hp':hp]
 dw.writerow(data)

Note that your whole code can also be simplified if you populate the data dictionary instead of all your if/else:

data={} #empty dictionary

#First extract everything that is on the main level of your dict
for key in ("name", "id", "order", "height", "weight":
    if key in data_json:
        data[key]=data_json[key]
        
#Check if the "stats" dict exists in your JSON data
if 'stats' in data_json:    
    if 'base_stat' in data_json['stats']:
       data['base_stat']=data_json['stats']['base_stat']
    if 'stat' in data_json['stats']:
        statDict = data_json['stats']['stat']
        for key in ['hp', 'attack', 'defense', 'special-attack', 'special-defense', 'speed']:
            if key in statDict:
                data[key]=statDict[key]

Notes:

  1. I did not test this code, check it carefully, but I hope you get the idea
  2. You could add else to all if key in checks to include an error message if a stat is missing
  3. If you are sure that all keys will always be present, then you can skip a few of the if checks
like image 37
FlyingTeller Avatar answered Feb 02 '26 16:02

FlyingTeller



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!