Home > Software engineering >  AttributeError: 'NavigableString' object has no attribute 'keys' in Python
AttributeError: 'NavigableString' object has no attribute 'keys' in Python

Time:03-17

I am trying to dump the data from an array into the csv file but it gives the following error: AttributeError: 'NavigableString' object has no attribute 'keys' in python. The array has the data when I try to print it, but while trying to create a csv file it throws error.

This is the code I wrote:

import requests
import csv
from bs4 import BeautifulSoup as bs

global newsitems
def loadRSS():
    url="https://rss.nytimes.com/services/xml/rss/nyt/Africa.xml"
    resp=requests.get(url)
    with open('topnewsfeed.xml','wb') as f:
        f.write(resp.content)

def extractData():
    infile = open("topnewsfeed.xml","r",encoding='utf-8')
    contents = infile.read()
    soup = bs(contents,'xml')
    guids= soup.find_all('guid')
    titles = soup.find_all('title')
    pubDates= soup.find_all('pubDate')
    descs= soup.find_all('description')
    links= soup.find_all('link')
    newsitems=[]
    for (guid,title,pubDate,desc,link) in zip(guids,titles,pubDates,descs,links):
        newsitems.append(guid.string)
        newsitems.append(title.string)
        newsitems.append(pubDate.string)
        newsitems.append(desc.string)
        newsitems.append(link.string)
    return newsitems

def savetoCSV(array,filename):
    fields=['Guid','Title','PubDate','Description','Link']
    with open(filename,'w') as csvfile:
        writer=csv.DictWriter(csvfile,fieldnames=fields)
        writer.writeheader()
        writer.writerows(array)
             
def run():
    loadRSS()
    newsitems=extractData()
    savetoCSV(newsitems,'topnews.csv')
run()

CodePudding user response:

writerows of DictWriter expects a sequence of dicts (with fieldnames as keys mapping to values), not a sequence of NavigableString objects, which is what newsitems is.

Instead of making a sequence of navigable strings:

    for (guid,title,pubDate,desc,link) in zip(guids,titles,pubDates,descs,links):
        newsitems.append(guid.string)
        newsitems.append(title.string)
        newsitems.append(pubDate.string)
        newsitems.append(desc.string)
        newsitems.append(link.string)

Make a list of dictionaries, as is expected by writerows. The keys in the dict should match your CSV field ('Guid','Title','PubDate','Description','Link')

    for (guid,title,pubDate,desc,link) in zip(guids,titles,pubDates,descs,links):
        newsitems.append({
                          'Guid': guid.string,
                          'Title': title.string,
                          'PubDate': pubDate.string,
                          'Description': desc.string,
                          'Link': link.string
                         }
        )
  • Related