web-dev-qa-db-ja.com

ValueError:ast.literal_evalを使用した不正な形式の文字列

私はjson apiを取得するためにループを行っています、これは私のループにあるものです:

response_item = requests.request('GET',url_item,params=None,verify=False)
response_item = json.loads(response_item.text)
response_item = ast.literal_eval(json.dumps(response_item, ensure_ascii=False).encode('utf8'))

45000個のjsonオブジェクトをスキャンして、反復ごとに "url_item"変数を生成します。各オブジェクトは同じで、7000オブジェクトのようなものを取得でき、7064番目に到達すると次のエラーが発生します。

Traceback (most recent call last):
  File "C:\Python27\tools\api_item.py", line 47, in <module>
    response_item = ast.literal_eval(json.dumps(response_item, ensure_ascii=False).encode('utf8'))
  File "C:\Python27\lib\ast.py", line 80, in literal_eval
    return _convert(node_or_string)
  File "C:\Python27\lib\ast.py", line 63, in _convert
    in Zip(node.keys, node.values))
  File "C:\Python27\lib\ast.py", line 62, in <genexpr>
    return dict((_convert(k), _convert(v)) for k, v
  File "C:\Python27\lib\ast.py", line 63, in _convert
    in Zip(node.keys, node.values))
  File "C:\Python27\lib\ast.py", line 62, in <genexpr>
    return dict((_convert(k), _convert(v)) for k, v
  File "C:\Python27\lib\ast.py", line 79, in _convert
    raise ValueError('malformed string')
ValueError: malformed string

2つ目と3つ目の「response_item」を印刷するのが常でした。もちろん、この場合、3つ目のエラーメッセージは表示されません。これは、直前にエラーが発生したためです。ここでは、json.loadの後に出力したものを示します。

{u'restrictions': [], u'name': u'Sac \xe0 dos de base', u'level': 0, u'rarity': u'Basic', u'vendor_value': 11, u'details': {u'no_sell_or_sort': False, u'size': 20}, u'game_types': [u'Activity', u'Wvw', u'Dungeon', u'Pve'], u'flags': [u'NoSell', u'SoulbindOnAcquire', u'SoulBindOnUse'], u'icon': u'https://render.guildwars2.com/file/80E36806385691D4C0910817EF2A6C2006AEE353/61755.png', u'type': u'Bag', u'id': 8932, u'description': u'Un sac de 20 emplacements pour les personnages d\xe9butants.'}

これより前に入手したアイテムはすべて同じタイプ、同じ形式で、7064番を除いてエラーはありません!

ご協力ありがとうございました!

10
Aurélien

JSONデータではnotast.literal_eval()を使用する必要があります。 JSONとPythonリテラルは同じように見えるlookかもしれませんが、ほとんど違います。

この場合、データにはブールフラグが含まれ、JSONではfalseに設定されます。適切なPython booleanはタイトルケースを使用するので、False

_>>> import json, ast
>>> s = '{"no_sell_or_sort": false, "size": 20}'
>>> json.loads(s)
{u'no_sell_or_sort': False, u'size': 20}
>>> ast.literal_eval(s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python2.7/ast.py", line 80, in literal_eval
    return _convert(node_or_string)
  File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python2.7/ast.py", line 63, in _convert
    in Zip(node.keys, node.values))
  File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python2.7/ast.py", line 62, in <genexpr>
    return dict((_convert(k), _convert(v)) for k, v
  File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python2.7/ast.py", line 79, in _convert
    raise ValueError('malformed string')
ValueError: malformed string
_

その他の違いには、nullの代わりにNoneを使用すること、およびPython 2の対象のUnicodeエスケープシーケンスがのように見える)が含まれます(バイト)string、非BMPコードポイントをエスケープするときにUTF-16サロゲートを使用します。

json.loads()ではなくast.literal_eval()を使用してデータをロードします。適切なJSONを適切に処理するだけでなく、より高速です

あなたの場合、json.dumps()を使用しているようですが、ast.literal_eval()を使用してデータを再度ロードしてみてください。そのステップにはno needがあり、あなたはalreadyにPythonオブジェクトがありました。

つまり、次の行:

_response_item = ast.literal_eval(json.dumps(response_item, ensure_ascii=False).encode('utf8'))
_

せいぜい冗長であり、最悪の場合は非常に間違っています。 _response_item_をJSON文字列に再エンコードしても、Pythonリテラルとして解釈できるものは生成されません。

29
Martijn Pieters