为什么会出现这个urllib错误?

10 投票
2 回答
7607 浏览
提问于 2025-04-17 07:52

我在使用urllib的时候遇到了一个奇怪的错误:

INFO     2011-12-07 07:02:45,101 main.py:884] urlhttp://maps.googleapis.com/maps/api/geocode/json?latlng=59.3333,18.05&sensor=false
WARNING  2011-12-07 07:02:45,103 urlfetch_stub.py:428] Stripped prohibited headers from URLFetch request: ['Host']
ERROR    2011-12-07 07:02:45,210 main.py:346] HTTPResponse instance has no attribute 'readline': 
Traceback (most recent call last):
  File "/media/Lexar/montao/lib/webapp2/webapp2.py", line 545, in dispatch
    return method(*args, **kwargs)
  File "/media/Lexar/montao/montaoproject/main.py", line 885, in get
    jsondata = json.load(urllib2.urlopen(url))
  File "/usr/lib/python2.7/urllib2.py", line 126, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 391, in open
    response = self._open(req, data)
  File "/usr/lib/python2.7/urllib2.py", line 409, in _open
    '_open', req)
  File "/usr/lib/python2.7/urllib2.py", line 369, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 1185, in http_open
    return self.do_open(httplib.HTTPConnection, req)
  File "/usr/lib/python2.7/urllib2.py", line 1176, in do_open
    resp = addinfourl(fp, r.msg, req.get_full_url())
  File "/media/Lexar/montao/google/appengine/dist27/urllib.py", line 978, in __init__
    addbase.__init__(self, fp)
  File "/media/Lexar/montao/google/appengine/dist27/urllib.py", line 926, in __init__
    self.readline = self.fp.readline
AttributeError: HTTPResponse instance has no attribute 'readline'

之前能正常工作的代码是

  url = 'http://maps.googleapis.com/maps/api/geocode/json' + \
    '?latlng={},{}&sensor=false'.format(entity.geopt.lat, entity.geopt.lon)
  logging.info('url%s' % url)
  jsondata = json.load(urllib2.urlopen(url))

你能告诉我这里有什么问题吗?我看到过有人说响应对象没有“get”这个方法,那为什么之前能用呢?我觉得可能是因为我把SDK从1.6升级到了1.6.1的预发布版本。可能还有其他一些区别,导致现在的代码出错,而之前的代码没问题。

谢谢你

更新

根据回答的内容,下面这种使用urlfetch的方式可以正常工作:

  url = 'http://maps.googleapis.com/maps/api/geocode/json' + \
    '?latlng={},{}&sensor=false'.format(entity.geopt.lat, entity.geopt.lon)
  logging.info('url%s' % url)

  from google.appengine.api import urlfetch
  result = urlfetch.fetch(url)
  jsondata = json.loads(result.content)

2 个回答

2

丢失了 Request() 方法?也许这样可以解决。

headers = { 'Content-Type' : 'application/json' } // Maybe 'application/xml'
data = None
req  = urllib2.Request(url, data, headers)    
resp = urllib2.urlopen(req)         
data = resp.read()
jsondata = json.load(data)

我在 Python 控制台里试了一下:

>>> import urllib2
>>> headers = { 'Content-Type' : 'application/json' }
>>> data = None
>>> req = urllib2.Request("http://maps.googleapis.com/maps/api/geocode/json?latlng=59.3333,18.05&sensor=false", data, headers)
>>> response = urllib2.urlopen(req)
>>> data = response.read()
>>> data

这样就能正确打印出数据。以下是我的结果:

14

这看起来是SDK的一个bug。我能复现出完全相同的情况。你为什么要用urllib2而不是urllib呢?

我使用的是Python2.7和SDK 1.6.1,测试了以下代码:

import urllib  
url = 'http://maps.googleapis.com/maps/api/geocode/json' + \
        '?latlng={},{}&sensor=false'.format(entity.geopt.lat, entity.geopt.lon)
logging.info('url%s' % url)
jsondata = json.load(urllib.urlopen(url))

结果是正常的。

如果我能找出导致文件读取错误的原因,我会继续跟进并提交一个bug。

注意:我测试了KJuly建议的代码,但也出现了同样的错误。看起来urllib2在不应该依赖urllib的时候却依赖了。还在深入调查。

编辑:因为urlliburllib2其实只是urlfetch的包装,所以我可能还会建议以下内容:

from google.appengine.api import urlfetch
result = urlfetch.fetch(url)
jsondata = json.loads(result.content)

第二次编辑:无论如何,我们使用的是本地版本的/usr/lib/python2.7/urllib2.py,它试图与GAE特定版本的urllibgoogle/appengine/dist27/urllib.py)进行交互。

撰写回答