web-dev-qa-db-fra.com

ValueError: chaîne mal formée utilisant ast.literal_eval

Je fais une boucle pour obtenir json api, voici ce que j'ai dans ma boucle:

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'))

Je scanne environ 45 000 objets json, je génère une variable "url_item" pour chaque itération. Chaque objet est le même, je peux obtenir quelque chose comme un objet 7000 et j'ai l'erreur suivante lorsque j'atteins le 7064e:

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

J'avais l'habitude d'imprimer les deuxième et troisième "response_item". Bien sûr, dans ce cas, le troisième ne s'affiche pas car j'ai l'erreur juste avant, voici ce que j'ai pour l'impression après le 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.'}

Chaque élément que je reçois avant celui-ci a le même type, le même format, et je n'ai aucune erreur, sauf pour le 7064e!

Merci de votre aide!

10
Aurélien

Vous devez pas utiliser ast.literal_eval() sur les données JSON. JSON et Python littéraux peuvent ressembler à la même chose, mais ils ne le sont pas du tout.

Dans ce cas, vos données contiennent un indicateur booléen, défini sur false en JSON. Un booléen Python booléen utilise la casse du titre, donc 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

D'autres différences incluent l'utilisation de null au lieu de None et des séquences d'échappement Unicode dans quoi Python 2 ressemble à un plain (octets) chaîne , utilisant des substituts UTF-16 lors de l'échappement de points de code non BMP.

Chargez vos données avec json.loads(), pas ast.literal_eval(). Non seulement il gérera très bien le JSON, mais il est aussi plus rapide .

Dans votre cas, il semble que vous utilisez json.dumps() puis essayez de charger à nouveau les données avec ast.literal_eval(). Il y a pas besoin pour cette étape, vous déjà aviez un objet Python.

En d'autres termes, la ligne:

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

est redondant au mieux, et très, très mal, au pire. Le recodage de response_item En une chaîne JSON ne produit pas quelque chose qui peut être interprété comme un littéral Python.

29
Martijn Pieters