【问题标题】:Why am I getting an IndexError for a (seemingly) properly-split string?为什么我得到一个(看似)正确拆分的字符串的 IndexError?
【发布时间】:2012-10-31 20:28:36
【问题描述】:

我目前有一个脚本应该获取并返回 Bit.ly 链接的点击次数。我首先从 Bitly url 收集和读取数据,这似乎是正确的。

    bitly_data = "https://api-ssl.bitly.com/v3/link/clicks?access_token=ACCESS_TOKEN&link=http://bit.ly/"+link
    src = urllib2.urlopen(bitly_data)
    src = src.read()

linkTY8lnd 之类的东西时,src 是一个看起来像这样的字符串

{“status_code”:200,“数据”:{“单位”:-1,“tz_offset”:-4,“单位”: "day", "link_clicks": 535}, "status_txt": "OK"}

我现在想解析这个字符串以获取link_clicks 之后的数值。我认为最好的方法是进行两次拆分。

    src=src.split('clicks": ')
    src = str(src[1])
    clicks = src.split('}, "status')
    clicks = clicks[0]

当我运行它时,clicks 最终会等于正确的数字,并且仅此而已。但是,终端为行 src = str(src[1]) 返回一个 IndexError。我试图摆脱str(),但这没有效果。尽管最终值已得到纠正,但如果能理解为什么我会收到此错误,将不胜感激。

这是完整的 Traceback:

Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/Flask-0.9-py2.7.egg/flask/app.py", line 1701, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Library/Python/2.7/site-packages/Flask-0.9-py2.7.egg/flask/app.py", line 1689, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Library/Python/2.7/site-packages/Flask-0.9-py2.7.egg/flask/app.py", line 1687, in wsgi_app
    response = self.full_dispatch_request()
  File "/Library/Python/2.7/site-packages/Flask-0.9-py2.7.egg/flask/app.py", line 1360, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Library/Python/2.7/site-packages/Flask-0.9-py2.7.egg/flask/app.py", line 1358, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Library/Python/2.7/site-packages/Flask-0.9-py2.7.egg/flask/app.py", line 1344, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/Zach/Dropbox/bitly/bit.py", line 35, in settings
    src = str(src[1])
IndexError: list index out of range

提前谢谢你。

【问题讨论】:

    标签: python indexing split urllib2


    【解决方案1】:

    这个响应是json,因此,解码json而不是尝试解析字符串。

    >>> import json
    >>> resp = '{"status_code": 200, "data": {"units": -1, "tz_offset": -4, "unit": "day", "link_clicks": 535}, "status_txt": "OK"}'
    >>> resp_object = json.loads(resp)
    >>> resp_object and resp_object.get('data', {}).get('link_clicks', 0) or 0
    535
    

    【讨论】:

    • 感谢您的快速帮助!不过,按照您的指示,我似乎收到了一个 TypeError: TypeError: 'NoneType' object is not subscriptable 虽然再次返回了正确的点击次数。
    • 提供执行此操作的代码。如果你得到一个TypeError 但仍然得到一个值,那么你正在运行多个请求或其他一些时髦的事情正在发生。如果您使用None 代替有效对象,那么您将无需点击。
    • 如果你在 resp_object 中得到 None,那么你可以明确地检查它,或者像我上面的最后一行更新和 None 的情况一样进行更新,以及丢失 datalink_clicks结果至少应该显示0
    • 对。我仍然只是使用上面的示例进行尝试,因此返回 None 应该不是问题。将其更改为更新后的行会返回点击次数,但现在是 AttributeError: AttributeError: 'NoneType' object has no attribute 'get'
    • 我的更新代码是:bitly_data = "https://api-ssl.bitly.com/v3/link/clicks?access_token=ACCESS_TOKEN&link=http://bit.ly/"+link src = urllib2.urlopen(bitly_data) src = src.read() clicks = json.loads(src) clickamnt = clicks.get('data', {}).get('link_clicks', 0) or 0
    【解决方案2】:

    src 看起来像是 JSON。为什么不用json模块直接读取呢?

    无论出于何种原因,如果您不想使用json,请继续阅读:

    该错误是由于您假设您拆分的子字符串存在于您拆分的字符串中,即'clicks": ' 确实是src 的子字符串。如果不是这种情况(因为我怀疑它不是在引发错误时),那么split 返回一个列表,其中只有一个元素,该元素是src

    如果你更喜欢这种情况,src[1] 应该在调用src = src.split('clicks": ') 后给你一个空字符串,那么你最好使用str.partition

    In [5]: somestr = 'prefixclicks: "suffix'
    
    In [6]: somestr.partition('clicks: "')
    Out[6]: ('prefix', 'clicks: "', 'suffix')
    
    In [7]: somestr.partition('clicks: "')[-1]
    Out[7]: 'suffix'
    
    In [8]: somestr = 'prefixsuffix'
    
    In [9]: somestr.partition('clicks: "')
    Out[9]: ('prefixsuffix', '', '')
    
    In [10]: somestr.partition('clicks: "')[-1]
    Out[10]: ''
    

    希望对你有帮助

    【讨论】:

      【解决方案3】:

      你可以试试这个找出link_clicks的值,使用ast.literal_eval()

      In [14]: import ast
      
      In [15]: src=`{"status_code": 200, "data": {"units": -1, "tz_offset": -4, "unit": "day", "link_clicks": 535}, "status_txt": "OK"}`
      
      In [16]: d=ast.literal_eval(src)
      
      In [17]: d["data"]["link_clicks"]
      Out[17]: 535
      

      【讨论】:

      • literal_eval 如果您不信任 evaling 的字符串,可能会非常危险
      • @inspectorG4dget 我认为是eval(),这被认为是危险的。正如文档所说 this can be used for safely evaluating strings containing Python expressions from untrusted sources without the need to parse the values oneself. docs.python.org/2/library/ast.html#ast.literal_eval
      • literal_eval 仅评估简单类型,因此没有真正的危险,但我不相信(我可能错了)所有 json 都总是可以以这种方式解析并且如果不是,则此方法可能会在某些时候产生异常。
      • ast.literal_eval 解析python文字语法; json.loads 解析 JSON 语法。它们相似但略有不同(例如,python 中的 True/False 与 JSON 中的 true/false;只有 python 允许单引号字符串;只有 JSON 有 nan 文字,...)所以使用正确的很重要。 Web API 更有可能返回 JSON,the case for bit.ly 也是如此。
      猜你喜欢
      • 1970-01-01
      • 2014-03-10
      • 2022-08-11
      • 1970-01-01
      • 1970-01-01
      • 2011-12-29
      • 1970-01-01
      • 2020-10-16
      • 1970-01-01
      相关资源
      最近更新 更多