【问题标题】:ValueError: malformed string using ast.literal_evalValueError:使用 ast.literal_eval 的格式错误的字符串
【发布时间】:2015-12-18 04:21:13
【问题描述】:

我正在循环获取 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

我曾经打印过第二个和第三个“response_item”。当然,在这种情况下,第三个没有显示,因为我之前遇到了错误,这里是我在 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 个,我没有任何错误!

感谢您的帮助!

【问题讨论】:

  • 你为什么首先在json.dumps()的输出上使用ast.literal_eval()
  • 是否推荐使用output = json.dumps(json.load(fdobject))而不是ast.literal_eval

标签: python json string python-requests malformed


【解决方案1】:

您应该对 JSON 数据使用 ast.literal_eval()。 JSON 和 Python 字面量可能看起来相似,但实际上并非如此。

在这种情况下,您的数据包含一个布尔标志,在 JSON 中设置为 false。正确的 Python 布尔值使用标题大小写,所以 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 转义序列看起来像 普通(字节)字符串,在转义非BMP 代码点。

使用json.loads() 加载您的数据,而不是ast.literal_eval()。它不仅可以很好地处理正确的 JSON,而且还更快

在您的情况下,您似乎正在使用json.dumps(),然后尝试使用ast.literal_eval() 再次加载数据。 不需要该步骤,您已经拥有一个 Python 对象。

换句话说,行:

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

充其量是多余的,最坏的情况是非常非常错误。将response_item 重新编码为 JSON 字符串不会产生可以解释为 Python 文字的内容。

【讨论】:

  • 更安全,我想补充一下。
  • @Kroltan:ast.literal_eval() 非常安全。它将字符串解析为抽象语法树,然后仅将文字(字符串、列表、数字等)映射到 Python 对象。其他一切都会引发异常。
  • 我已经删除了你告诉我的带有 ast.literal_eval() 的行。现在我没有错误,但是我有一些带有 unicode 字符 "u'" 的东西,我已经尝试了很多方法来删除这些字符,因为它们随后被插入到数据库中。这就是为什么我在 ast.. 中添加这一行的原因。
  • @Aurélien:所有 JSON 数据都是 Unicode 数据。如果您看到 u 前缀出现在您的数据库中,那么您有一个不同的问题,您将 repr(value) 插入数据库而不是 value 本身。
  • @Aurélien:也许您可以发布一个 问题,其中包含如何将数据插入数据库的示例。 u'...' 对象是 Python Unicode 文本对象,前缀用于区分类型和 Python 字节串。
【解决方案2】:

ast.literal_eval 如果您使用 SQL 注入是安全的。 因为当插入不需要的章程时,它会显示 Syntex 错误,从而阻止注入。

【讨论】:

  • 这与SQL注入无关。而且 SQL 注入依赖于字符串 contents,而不是类型。
  • 评论者注意:这不应该首先被标记为质量非常低,因为 VLQ 队列不是为了技术不准确 - 这就是 downvoting 和 cmets 的用途。这已经被否决了,并附有解释为什么不正确的评论,因此无需采取进一步行动。
  • 所以点击在审核队列中看起来没问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-14
  • 1970-01-01
  • 2019-01-13
  • 2016-09-06
  • 2013-12-05
  • 2020-10-10
相关资源
最近更新 更多