【问题标题】:How do I prevent Python's urllib(2) from following a redirect如何防止 Python 的 urllib(2) 跟随重定向
【发布时间】:2010-10-07 22:54:42
【问题描述】:

我目前正在尝试使用 Python 登录一个站点,但是该站点似乎在同一页面上发送了一个 cookie 和一个重定向语句。 Python 似乎遵循该重定向,因此阻止我读取登录页面发送的 cookie。如何防止 Python 的 urllib(或 urllib2)urlopen 跟随重定向?

【问题讨论】:

标签: python urllib2


【解决方案1】:

urllib2.urlopen 调用使用此处理程序类列表的build_opener()

handlers = [ProxyHandler, UnknownHandler, HTTPHandler,
HTTPDefaultErrorHandler, HTTPRedirectHandler,
FTPHandler, FileHandler, HTTPErrorProcessor]

您可以尝试使用省略HTTPRedirectHandler 的列表自己调用urllib2.build_opener(handlers),然后在结果上调用open() 方法以打开您的URL。如果你真的不喜欢重定向,你甚至可以调用urllib2.install_opener(opener) 到你自己的非重定向开启者。

听起来你真正的问题是urllib2 没有按照你想要的方式做 cookie。另见How to use Python to login to a webpage and retrieve cookies for later usage?

【讨论】:

  • 您可以尝试自己调用 urllib2.build_opener(handlers) 并使用省略 HTTPRedirectHandler 的列表,然后在结果上调用 open() 方法来打开您的 URL。 urllib2.build_opener() 的文档说这个以下类的实例将在处理程序的前面,除非处理程序包含它们、它们的实例或它们的子类:ProxyHandler、UnknownHandler、 HTTPHandler、HTTPDefaultErrorHandler、HTTPRedirectHandler、FTPHandler、FileHandler、HTTPErrorProcessor。 看起来省略 HTTPRedirectHandler 不起作用...
【解决方案2】:

这个问题是在here 之前提出的。

编辑:如果您必须处理古怪的网络应用程序,您可能应该尝试mechanize。这是一个很棒的库,可以模拟 Web 浏览器。您可以控制重定向、cookie、页面刷新...如果网站不[严重] 依赖 JavaScript,您将与 mechanize 相处得很好。

【讨论】:

    【解决方案3】:

    你可以做几件事:

    1. 构建自己的 HTTPRedirectHandler 来拦截每个重定向
    2. 创建一个 HTTPCookieProcessor 实例并安装该开启程序,以便您可以访问 cookiejar。

    这是一个快速的小东西,显示了两者

    import urllib2
    
    #redirect_handler = urllib2.HTTPRedirectHandler()
    
    class MyHTTPRedirectHandler(urllib2.HTTPRedirectHandler):
        def http_error_302(self, req, fp, code, msg, headers):
            print "Cookie Manip Right Here"
            return urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
    
        http_error_301 = http_error_303 = http_error_307 = http_error_302
    
    cookieprocessor = urllib2.HTTPCookieProcessor()
    
    opener = urllib2.build_opener(MyHTTPRedirectHandler, cookieprocessor)
    urllib2.install_opener(opener)
    
    response =urllib2.urlopen("WHEREEVER")
    print response.read()
    
    print cookieprocessor.cookiejar
    

    【讨论】:

    • 您似乎根本没有在示例中使用redirect_handler = urllib2.HTTPRedirectHandler()。你要展示第二个例子吗?
    • 你是对的,我没有使用redirect_handler。相反,我创建了自己的重定向处理程序。我将编辑删除。
    • 为什么不需要实例化MyHTTPRedirectHandler,而是将类传递给build_opener()方法?
    • 来自文档:处理程序可以是 BaseHandler 的实例,也可以是 BaseHandler 的子类(在这种情况下,必须可以在没有任何参数的情况下调用构造函数)。由于 MyHTTPRedirectHandler 没有带任何参数的构造函数,我可以按原样传入。
    【解决方案4】:

    如果您只需要停止重定向,那么有一种简单的方法可以做到这一点。例如,我只想获取 cookie,并且为了获得更好的性能,我不想被重定向到任何其他页面。我也希望代码保持为 3xx。让我们以 302 为例。

    class MyHTTPErrorProcessor(urllib2.HTTPErrorProcessor):
    
        def http_response(self, request, response):
            code, msg, hdrs = response.code, response.msg, response.info()
    
            # only add this line to stop 302 redirection.
            if code == 302: return response
    
            if not (200 <= code < 300):
                response = self.parent.error(
                    'http', request, response, code, msg, hdrs)
            return response
    
        https_response = http_response
    
    cj = cookielib.CookieJar()
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj), MyHTTPErrorProcessor)
    

    这样,你甚至不需要进入urllib2.HTTPRedirectHandler.http_error_302()

    更常见的情况是我们只是想停止重定向(根据需要):

    class NoRedirection(urllib2.HTTPErrorProcessor):
    
        def http_response(self, request, response):
            return response
    
        https_response = http_response
    

    通常这样使用它:

    cj = cookielib.CookieJar()
    opener = urllib2.build_opener(NoRedirection, urllib2.HTTPCookieProcessor(cj))
    data = {}
    response = opener.open('http://www.example.com', urllib.urlencode(data))
    if response.code == 302:
        redirection_target = response.headers['Location']
    

    【讨论】:

    • 正是我需要的,而且非常简洁 class NoRedirection() - 你甚至不必存储 code, msg, hdrs -- 谢谢 Alan。
    • 你是对的!我按照您的建议删除了该行。谢谢 Xtof。
    • 是否可以使用这种方法来获取实际的重定向 URL?
    • @Malvin9000 如果你想得到重定向的目标,那么是的,只要阅读response.headers['Location'],你就会得到:)
    • @Malvin9000 不是字面上使用读取,您可以将其分配给新变量或直接打印出来。让我更新答案,以便您查看。
    猜你喜欢
    • 2015-09-24
    • 2010-11-24
    • 2021-08-27
    • 1970-01-01
    • 2010-12-03
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    相关资源
    最近更新 更多