在Python中,为什么urllib.urlopen会使Google返回HTTP状态"302 Moved"?

3 投票
4 回答
1171 浏览
提问于 2025-04-17 23:20

我在CentOS 6.4上使用的是Python 2.6.6。

import urllib
#url = 'http://www.google.com.hk'    #ok
#url = 'http://clients1.google.com.hk'    #ok
#url = 'http://clients1.google.com.hk/complete/search'  #ok (blank)
url  = 'http://clients1.google.com.hk/complete/search?output=toolbar&hl=zh-CN&q=abc'  #fails
print url
page = urllib.urlopen(url).read()
print page

用前面三个网址,代码运行得很好。但是用到第四个网址时,Python却返回了一个302的状态码:

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://clients1.google.com.hk/complete/search?output=toolbar&amp;hl=zh-CN&amp;q=abc">here</A>.
</BODY></HTML>

我代码里的网址和它告诉我用的那个网址是一样的:

My URL:  http://clients1.google.com.hk/complete/search?output=toolbar&hl=zh-CN&q=abc
Its URL: http://clients1.google.com.hk/complete/search?output=toolbar&hl=zh-CN&q=abc

谷歌说这个网址已经移动了,但网址是一样的。有人知道这是为什么吗?

更新:所有的网址在浏览器里都能正常工作。但是在Python命令行中,第四个网址却返回了302。

4 个回答

0

如果你使用你喜欢的网页调试工具(对我来说是Fiddler),然后在浏览器中打开那个网址,你会看到你也收到了一个302的初始响应。你的浏览器很聪明,会自动帮你跳转到新的地址。所以你的代码返回的响应是正确的。如果你想让你的代码也能自动跳转到新的网址,那你就得让你的代码聪明到可以做到这一点。

2

我不知道为什么urllib会失败(我得到的回应是一样的),不过requests库工作得很好:

import requests
url = 'http://clients1.google.com.hk/complete/search?output=toolbar&hl=zh-CN&q=abc'    # fails
print (requests.get(url).text)
2

这可能跟请求的头部信息和可能的 cookies 有关。我在命令行上用 curl 做了个简单测试,结果也得到了 302 移动的提示。它提供的 Location 头部信息和文档里的不一样。如果我跟着正文里的 URL 走,我得到的是 204 响应(这有点奇怪)。如果我跟着 Location 头部走,就会出现你提到的循环响应。

可能比较重要的是 Set-Cookie 头部。它可能会一直重定向,直到设置了合适的 cookie。它也可能在检查 User-Agent,并根据这个做一些处理。这些都是浏览器和像 requests 或 urllib 这样的工具之间的主要区别。浏览器会创建会话,存储 cookies,并发送不同的头部信息。

2

urllib这个库没有处理cookies,导致它在发送新请求时没有带上cookies,这就造成了在那个网址上出现了重定向循环。为了处理这个问题,你可以使用urllib2(这个库更新得更好),并且添加一个处理cookies的功能:

import urllib2
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
response = opener.open('http://clients1.google.com.hk/complete/search?output=toolbar&hl=zh-CN&q=abc')
print response.read()

撰写回答