2017-11-28 4 views
2

以下のコードはlastfm APIを使用しているアーティストに関する情報を取得しています。次にbands[Name]に名前を保存し、アーティストの各タグ名(例:ロックなど)をbands[Tags].に保存します。名前を取得して保存するのに有効ですが、タグでは機能しません。それが表示されます。エラーを示すためにexemple作業XML要素の取得テキストが機能していません:AttributeError: 'NoneType'オブジェクトに 'findall'属性がありません

Traceback (most recent call last): 
     File "C:/Users/Ozzy/PycharmProjects/getData/getData.py", line 19, in <module> 
     for tag in artist.find('tags').findall('tag'): 
    AttributeError: 'NoneType' object has no attribute 'findall' 

最小:

import xml.etree.ElementTree as ET 
    import requests 

    ID = 1 

    chosen = "U2" 
    artist = requests.get(
     'http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist=U2&api_key=b088cbedecd40b35dd89e90f55227ac2') 
    tree = ET.fromstring(artist.content) 
    for child in tree: 
     for artist in child: 
      print(artist) 
      for tag in artist.find('tags').findall('tag'): 
       print(tag.find('name').text) 

応答は、この形式を持っている:コードが取得する

<lfm status="ok"> 
<artist> 
<name>U2</name> 
<tags> 
<tag> 
<name>rock</name> 
<url>https://www.last.fm/tag/rock</url> 
</tag> 
<tag> 
<tag> 
<name>alternative</name> 
<url>https://www.last.fm/tag/alternative</url> 
</tag> 
</tags> 
</artist> 
</lfm> 

全作業exempleを、特定の国のトップアーティストからの情報を収集し、 (それは上記NoneTypeエラーが表示されますので、作業各アーティストのタグを取得し、保存せずに)アーティスト:

import xml.etree.ElementTree as ET 
import requests 
import json 
ID = 1 

api_key = "b088cbedecd40b35dd89e90f55227ac2" 

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



# GET ARTIST INFO 
for i, v in bands.items(): 

    chosen = bands[i]['Name'].replace(" ", "+") 
    artist = requests.get(
     'http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist=' + chosen + '&api_key=' + api_key) 
    tree = ET.fromstring(artist.content) 
    for child in tree: 
     for artist in child: 
      #for tag in artist.find('tags').findall('tag'): 
       #print(tag.find('name').text) 
       #bands[i][Tags] = tag.find('name').text 


      if (artist.get('size') == "large"): 
       if (artist.text is not None): 
        bands[i]['Image'] = artist.text 
      for bio in artist.findall('summary'): 
       if (bio.text is not None): 
        bands[i]['Description'] = bio.text 
       else: 
        bands[i]['Description'] = bio.text 
    print(bands[i]['Name'] + " INFO RETRIEVED") 

with open('artists.json', 'w') as outfile: 
    json.dump(bands, outfile) 

with open('artists.json') as data_file: 
    bands = json.load(data_file) 

data_file.close() 

あなたがこの問題を解決する方法を知っていますか?

+0

はAttributeError同一の独立した動作をします。「NoneType」オブジェクトが属性を持っていない「のfindAll」これはartist.findを意味します( 'tags')はタグを見つけることができないので、Noneを返す –

+1

あなたの答えをありがとう。しかし、xmlレスポンスには "tags"要素があるので、うまくいくはずです。 – OzzyW

答えて

1

ループのレベルが深すぎます。

<lfm status="ok">  --> tree 
    <artist>    --> child in tree 
    <name>U2</name>   --> for artist in child 
    <tags>..</tags> 

<tagsはすでにchildの一部であり、したがって、artist.find('tags')Noneを返します。

あなたはにあなたのループを短くすることができます。

  • それはdict内のキーをループに簡単に、より効率的である以上for k in my_dictかを使用することにより:

    for band in bands.values():  
        url = 'http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist={}&api_key={}'.format(band['Name'], api_key) 
        artist = requests.get(url) 
        tree = ET.fromstring(artist.content) 
        if tree.find('artist') is None: 
         continue 
        for child in tree.find('artist').getchildren(): 
         if child.get('size') == "large": 
          if (child.text is not None): 
           band['Image'] = child.text 
         for bio in child.findall('summary'): 
          if bio.text is not None: 
           band['Description'] = bio.text 
          else: 
           band['Description'] = "" 
         for tag in child.findall('tag'): 
          if band.get('Tags'): 
           band['Tags'].append(tag.find('name').text) 
          else: 
           band['Tags'] = [tag.find('name').text] 
        print(band['Name'] + " INFO RETRIEVED") 
    

    いくつかの注意事項値はfor val in my_dict.values()

  • Tagsを上書きします。 listし、それに追加すると、あなたはすべての値を保存することを確認しますが
  • あなたif/else声明(if (bio.text is not None):)条件
+0

あなたの答えと説明をお寄せいただきありがとうございます。しかし、3番目の注釈を理解していない私は、XML要素のテキストを格納していない場合は、それが何も 'None'を格納していない場合、それは大丈夫ですか? – OzzyW

+0

どちらの場合でも 'bands [i] ['Description'] = bio.text'を使用していますが、' string'を取得した後は 'None'を取得します。文字列を使って何かしたいとしたら、 'None'というエラーが出ます。 –

+0

ああ、もう一度お気軽に! – OzzyW

関連する問題