2011-08-03 20 views
31

Tengo una URL y estoy usando HTTP GET para pasar una consulta a una página. Lo que sucede con el sabor más reciente (en net/http) es que el script no va más allá de la respuesta 302. He probado varias soluciones diferentes; HTTPClient, net/http, Rest-Client, Patron ...Ruby - net/http - siguientes redirecciones

Necesito una forma de continuar a la página final para validar una etiqueta de atributo en esas páginas html. La redirección se debe a que un agente de usuario móvil golpea una página que redirige a una vista móvil, por lo tanto, el agente de usuario móvil en el encabezado. Aquí está mi código como lo es hoy:

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 

¡Cualquier sugerencia sería muy apreciada!

+0

que utilizan [final_redirect_url] (https://rubygems.org/gems/final_redirect_url) joya para obtener la URL final después de varios cambios de dirección. – Indyarocks

Respuesta

51

Para seguir redirecciones, se puede hacer algo como esto (taken from ruby-doc)

Después de redirección

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) { |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/') 
+0

¿Alguna pista sobre cómo agregar un user-agent al encabezado? response = Net :: HTTP.get_response (URI.parse (uri_str.encode), {'User-Agent' => ua}) Lo intenté y parece que no funciona. Aparece el siguiente error: c: /Ruby191/lib/ruby/1.9.1/net/http.rb: 581: en 'initialize ': no ​​se puede convertir URI :: HTTP en String (TypeError) – r3nrut

+0

@ r3nrut: Ver mi edición – emboss

+1

Esto NO funciona para un enlace que se redirecciona a sí mismo pero agrega una barra invertida, por ejemplo, 'fetch ('http://epn.dk/okonomi2/dk/ECE5373277/chefoekonom-corydon-skyder-langt-over -mal ') ', la primera iteración, genera' # ', luego excepción ... –

1

Tal vez usted puede utilizar joya acera-fu aquí https://github.com/gdi/curb-fu lo único que es cierto código adicional para hazlo seguir redirigir. He usado lo siguiente antes. Espero eso ayude.

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 
+0

He tenido complicaciones para hacer que curb-fu funcione en mi máquina con Windows usando Ruby 1.9.1p430 ... Puedo hacer que funcione en mi Mac, pero como esto es algo que tengo que ejecutar en un servidor de Windows, necesito poner freno -fu para completar la instalación. Gracias por la sugerencia. – r3nrut

2

La referencia que trabajó para mí está aquí: http://shadow-file.blogspot.co.uk/2009/03/handling-http-redirection-in-ruby.html

En comparación con la mayoría de los ejemplos (incluyendo la respuesta aceptada aquí), es más robusto, ya que gestiona las direcciones URL que son sólo un dominio (http://example.com - necesita agregue a /), maneja SSL específicamente, y también URL relativas.

Por supuesto que sería mejor utilizar una biblioteca como RESTClient en la mayoría de los casos, pero a veces es necesario el detalle de bajo nivel.

5

Escribí otra clase para esto basada en los ejemplos que se dan aquí, muchas gracias a todos. He añadido galletas, parámetros y excepciones y, finalmente, tengo lo que necesito: 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') 
+0

¡Gracias por este fragmento de código! Creo que es posible que desee cerrar las conexiones http ('finish') para que no se filtren. ¡Muy apreciado! – gmcnaughton

+0

Definitivamente la mejor solución para mí hasta ahora. Podría trabajar fácilmente con la página con 'html_to_parse = Nokogiri :: HTML (UrlResolver.resolve ('http://www.ruby-lang.org'))' después. Gracias. – DemitryT

+0

No estoy seguro al 100%, pero en Ruby creo que cada objeto se destruye automáticamente cuando se sale del alcance de la función def. – sekrett

Cuestiones relacionadas