Urllib的urlopen在某些网站(如StackApps api)上出错:返回垃圾结果
我正在使用 urllib2
的 urlopen
函数,想从 StackOverflow 的 API 获取一个 JSON 结果。
我用的代码是:
>>> import urllib2
>>> conn = urllib2.urlopen("http://api.stackoverflow.com/0.8/users/")
>>> conn.readline()
我得到的结果是:
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x04\x00\xed\xbd\x07`\x1cI\x96%&/m\xca{\x7fJ\...
我对 urllib 还比较陌生,但这个结果看起来不太对。我在其他地方试过,得到的结果是我预期的(和用浏览器访问这个地址得到的 JSON 对象是一样的)。
在其他网站上使用 urlopen
(比如 "http://google.com")是没问题的,能正常返回 HTML 内容。我也试过使用 urllib
,结果也是一样。
我现在有点卡住了,不知道该从哪里入手解决这个问题。有没有什么建议?
1 个回答
这看起来有点像你要给 pickle 处理的数据。可能是 urllib2 发送的 User-Agent 字符串或 Accepts 头部中的某些内容,导致 StackOverflow 返回的不是 JSON 格式的数据。
一个明显的迹象是查看 conn.headers.headers
,看看 Content-Type 头部显示了什么。
还有这个问题,API 调用返回奇怪字符串格式的结果,可能会给你答案。基本上,你可能需要用 gzip 解压缩工具来处理你的结果。
可以用这段代码再确认一下:
>>> req = urllib2.Request("http://api.stackoverflow.com/0.8/users/",
headers={'Accept-Encoding': 'gzip, identity'})
>>> conn = urllib2.urlopen(req)
>>> val = conn.read()
>>> conn.close()
>>> val[0:25]
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x04\x00\xed\xbd\x07`\x1cI\x96%&/m\xca{\x7fJ'
是的,你确实收到了 gzip 编码的数据。
因为你在不同的机器上用相同版本的 Python 得到的结果不一样,而且一般来说,urllib2 API 需要你做一些特别的请求才能获取 gzip 编码的数据,我猜测你的网络中可能有一个透明代理。
我在 2009 年的 CodeCon 上看过 EFF 的一个演讲。他们在做端到端的连接测试,以发现各种各样的网络服务提供商的恶劣手段。在这个测试中,他们发现很多普通的 NAT 路由器会添加随机的 HTTP 头部或者做透明代理。你可能在你的网络中有某个设备正在添加或修改 Accept-Encoding
头部,以让你的连接看起来更快。