你不应该像那样使用requests.head,因为默认情况下它会跟随 302 重定向多达 3 次。
您可以禁用重定向(使用retries=False)并使用urlopen。然后返回的响应将始终将 302 内容作为其 url:
urlopen(method, url, body=None, headers=None, retries=None,
redirect=True, assert_same_host=True, timeout=<object object>,
pool_timeout=None, release_conn=None, chunked=False, body_pos=None,
**response_kw)
从池中获取连接并执行 HTTP 请求。这是发出请求的最低级别调用,因此您需要指定所有原始详细信息。
Parameters:
method – HTTP request method (such as GET, POST, PUT, etc.)
body – Data to send in the request body (useful for creating POST requests, see HTTPConnectionPool.post_url for more convenience).
headers – Dictionary of custom headers to send, such as User-Agent, If-None-Match, etc. If None, pool headers are used. If provided, these headers completely replace any pool-specific headers.
retries (Retry, False, or an int.) –
Configure the number of retries to allow before raising a MaxRetryError exception.
Pass None to retry until you receive a response. Pass a Retry object for fine-grained control over different types of retries. Pass an integer number to retry connection errors that many times, but no other types of errors. Pass zero to never retry.
这是相关的注释:
如果False,则禁用重试并立即引发任何异常。此外,不会在重定向时引发MaxRetryError,而是会返回重定向响应。
示例
(我实际上在本地 Web 服务器上运行了一项不同的测试,但找不到提供 错误 302 请求的公共测试)。
from urllib3 import PoolManager
manager = PoolManager(10)
req = manager.urlopen("GET", "http://en.wikipedia.org/wiki/Claude_E._Shannon", retries=False)
print req.get_redirect_location()
上面会从维基百科请求一个 HTTP 页面,从而生成到 HTTPS 的重定向:
https://en.wikipedia.org/wiki/Claude_E._Shannon
重定向加不重试
你的情况有点不同。您希望进行重定向,因为原始 URL 在第一次尝试时不会产生真正的重定向,但您希望获得失败的重定向。
这里的问题是 重定向由与错误重试相同的代码处理,因此您不能只禁用后者。两者都不是,也不是两者兼有。
然后您必须同时启用两者,并长期执行(拦截错误)。 您可能需要增加重试次数,这会在发生错误时减慢速度。
try:
// Did not know you can't post a URL shortener in a SO answer. Live and learn.
req = manager.urlopen("GET", "http(COLON)(SLASH)(SLASH)t(DOT)co(SLASH)eWWk8s8Hzj")
loc = req.get_redirect_location()
except MaxRetryError as fail:
// build "loc" from scheme, host and url
loc = "%s://%s%s" % (fail.pool.scheme, fail.pool.host, fail.url)
print loc
您的具体情况
由于您使用的是 urllib3 包装器,因此您只需解开异常:
try:
# This is your existing code
return requests.head(url, allow_redirects = True).url
except requests.ConnectionError as fail:
return "%s://%s%s" % (fail.args[0].pool.scheme, fail.args[0].pool.host, fail.args[0].url)
不过,您应该提供其他可能的错误。