【问题标题】:Ruby - net/http - following redirectsRuby - net/http - 以下重定向
【发布时间】:2011-10-19 12:52:31
【问题描述】:

我有一个 URL,我正在使用 HTTP GET 将查询传递到页面。最新版本(net/http)发生的情况是脚本没有超出 302 响应。我尝试了几种不同的解决方案; HTTPClient、net/http、Rest-Client、Patron...

我需要一种方法来继续到最后一页,以验证该页面 html 上的属性标记。重定向是由于移动用户代理点击了重定向到移动视图的页面,因此标题中的移动用户代理。这是我今天的代码:

require 'uri'
require 'net/http'

class Check_Get_Page

    def more_http
        url = URI.parse('my_url')
        req, data = Net::HTTP::Get.new(url.path, {
        'User-Agent' => 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5'
        })
        res = Net::HTTP.start(url.host, url.port) {|http|
        http.request(req)
            }
        cookie = res.response['set-cookie']
        puts 'Body = ' + res.body
        puts 'Message = ' + res.message
        puts 'Code = ' + res.code
        puts "Cookie \n" + cookie
    end

end

m = Check_Get_Page.new
m.more_http

任何建议将不胜感激!

【问题讨论】:

标签: ruby curl http-headers httpclient net-http


【解决方案1】:

要跟踪重定向,您可以执行以下操作 (taken from ruby-doc)

跟随重定向

require 'net/http'
require 'uri'

def fetch(uri_str, limit = 10)
  # You should choose better exception.
  raise ArgumentError, 'HTTP redirect too deep' if limit == 0

  url = URI.parse(uri_str)
  req = Net::HTTP::Get.new(url.path, { 'User-Agent' => 'Mozilla/5.0 (etc...)' })
  response = Net::HTTP.start(url.host, url.port, use_ssl: true) { |http| http.request(req) }
  case response
  when Net::HTTPSuccess     then response
  when Net::HTTPRedirection then fetch(response['location'], limit - 1)
  else
    response.error!
  end
end

print fetch('http://www.ruby-lang.org/')

【讨论】:

  • 这不适用于重定向到自身但添加反斜杠的链接,例如fetch('http://epn.dk/okonomi2/dk/ECE5373277/chefoekonom-corydon-skyder-langt-over-mal'),第一次迭代,它生成#<Net::HTTPMovedPermanently 301 Moved Permanently readbody=true>,然后异常...
  • 这在response['Location'] 是相对路径时不起作用,例如:'/inbox'。在这种情况下,需要设置原始uri的路径,例如:url.path = response['Location']
  • 你在哪里定义 ua 变量?
  • @DavidMoles -- 例如,http://www.puzzledragonx.com/en/monster.asp?n=9999 -- curl 显示带有 Location: / 标头的 302 重定向,并且上面的代码模式在没有 @MattHuggins 建议的情况下会阻塞。或者更确切地说,稍微调整一下——创建新的new_uri = URI.parse(response['Location']) 然后if new_uri.relative? 设置new_uri.scheme = uri.scheme' and 'new_uri.host = uri.host——否则,如果您尝试更新原始路径,那么任何查询或片段部分仍将保留在原始 uri 中。
  • @MattHuggins, @DreadPirateShawn:不要复制特定的 URI 属性,而是使用 URI.join(old_uri, new_location)。这将保留旧 URI 中 new_location 中未指定的任何属性,但如果提供了新方案或主机名,则使用它们。
【解决方案2】:

给定一个重定向的 URL

url = 'http://httpbin.org/redirect-to?url=http%3A%2F%2Fhttpbin.org%2Fredirect-to%3Furl%3Dhttp%3A%2F%2Fexample.org'

A. Net::HTTP

begin
  response = Net::HTTP.get_response(URI.parse(url))
  url = response['location']
end while response.is_a?(Net::HTTPRedirection)

确保在重定向过多时处理这种情况。

B. OpenURI

open(url).read

OpenURI::OpenRead#open 默认跟随重定向,但不限制重定向次数。

【讨论】:

    【解决方案3】:

    我根据此处给出的示例为此编写了另一个课程,非常感谢大家。我添加了cookie、参数和异常,终于得到了我需要的东西:https://gist.github.com/sekrett/7dd4177d6c87cf8265cd

    require 'uri'
    require 'net/http'
    require 'openssl'
    
    class UrlResolver
      def self.resolve(uri_str, agent = 'curl/7.43.0', max_attempts = 10, timeout = 10)
        attempts = 0
        cookie = nil
    
        until attempts >= max_attempts
          attempts += 1
    
          url = URI.parse(uri_str)
          http = Net::HTTP.new(url.host, url.port)
          http.open_timeout = timeout
          http.read_timeout = timeout
          path = url.path
          path = '/' if path == ''
          path += '?' + url.query unless url.query.nil?
    
          params = { 'User-Agent' => agent, 'Accept' => '*/*' }
          params['Cookie'] = cookie unless cookie.nil?
          request = Net::HTTP::Get.new(path, params)
    
          if url.instance_of?(URI::HTTPS)
            http.use_ssl = true
            http.verify_mode = OpenSSL::SSL::VERIFY_NONE
          end
          response = http.request(request)
    
          case response
            when Net::HTTPSuccess then
              break
            when Net::HTTPRedirection then
              location = response['Location']
              cookie = response['Set-Cookie']
              new_uri = URI.parse(location)
              uri_str = if new_uri.relative?
                          url + location
                        else
                          new_uri.to_s
                        end
            else
              raise 'Unexpected response: ' + response.inspect
          end
    
        end
        raise 'Too many http redirects' if attempts == max_attempts
    
        uri_str
        # response.body
      end
    end
    
    puts UrlResolver.resolve('http://www.ruby-lang.org')
    

    【讨论】:

    • 感谢此代码 sn-p!我认为您可能想要关闭 http 连接 (finish),但这样它们就不会泄漏。非常感谢!
    • 到目前为止对我来说绝对是最好的解决方案。之后我可以轻松地使用html_to_parse = Nokogiri::HTML(UrlResolver.resolve('http://www.ruby-lang.org')) 处理该页面。谢谢。
    • 我不确定 100%,但在 Ruby 中,我认为每个对象在超出 def 函数范围时都会自动销毁。
    • 也可以使用url.request_uri代替手动构造path,它包含查询参数。
    • @gmcnaughton,很好。你能在 Github 上向我发送拉取请求吗?
    【解决方案4】:

    对我有用的参考在这里:http://shadow-file.blogspot.co.uk/2009/03/handling-http-redirection-in-ruby.html

    与大多数示例(包括此处接受的答案)相比,它更强大,因为它可以处理只是域的 URL(http://example.com - 需要添加 /),专门处理 SSL 以及相对 URL。

    当然,在大多数情况下,最好使用 RESTClient 之类的库,但有时底层细节是必要的。

    【讨论】:

      【解决方案5】:

      也许你可以在https://github.com/gdi/curb-fu 使用curb-fu gem,唯一的事情是一些额外的代码让它跟随重定向。我以前用过以下。希望对您有所帮助。

      require 'rubygems'
      require 'curb-fu'
      
      module CurbFu
        class Request
          module Base
            def new_meth(url_params, query_params = {})
              curb = old_meth url_params, query_params
              curb.follow_location = true
              curb
            end
      
            alias :old_meth :build
            alias :build :new_meth
          end
        end
      end
      
      #this should follow the redirect because we instruct
      #Curb.follow_location = true
      print CurbFu.get('http://<your path>/').body
      

      【讨论】:

      • 我在使用 Ruby 1.9.1p430 让我在 Windows 机器上工作时遇到了复杂的问题......我可以让它在我的 Mac 上工作,但因为这是我必须运行的东西在 Windows 服务器上,我需要 curl-fu 来完成安装。感谢您的建议。
      【解决方案6】:

      如果你不需要关心每次重定向的细节,你可以使用库Mechanize

      require 'mechanize'
      
      agent = Mechanize.new
      begin
          response = @agent.get(url)
      rescue Mechanize::ResponseCodeError
          // response codes other than 200, 301, or 302
      rescue Timeout::Error
      rescue Mechanize::RedirectLimitReachedError
      rescue StandardError
      end
      

      它将返回目标页面。 或者您可以通过以下方式关闭重定向:

      agent.redirect_ok = false
      

      或者您可以根据要求更改一些设置

      agent.user_agent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Mobile Safari/537.36"
      

      【讨论】:

        猜你喜欢
        • 2012-05-16
        • 2016-10-06
        • 2010-10-03
        • 2017-05-28
        • 2018-01-24
        • 2011-01-14
        • 1970-01-01
        • 2023-03-10
        • 2012-08-22
        相关资源
        最近更新 更多