Guia Completo de Proxies HTTP em Ruby: Net::HTTP, Typhoeus e ProxyHat SDK

Aprenda a usar proxies HTTP em Ruby com Net::HTTP, Typhoeus para requisições paralelas, e ProxyHat SDK para rotação automática de IPs e geo-targeting. Exemplos de código prontos para produção.

Guia Completo de Proxies HTTP em Ruby: Net::HTTP, Typhoeus e ProxyHat SDK

Se você está construindo pipelines de dados, scrapers ou sistemas de monitoramento em Ruby, eventualmente precisará rotear requisições através de proxies. Seja para evitar rate limits, contornar bloqueios geográficos ou distribuir requisições entre múltiplos IPs, dominar o uso de proxies HTTP é essencial.

Este guia cobre três abordagens: a biblioteca padrão Net::HTTP, o poderoso Typhoeus com suporte a requisições paralelas, e o ProxyHat SDK para rotação automática e geo-targeting. Todos os exemplos são prontos para produção, com tratamento de erros e configurações de TLS.

Net::HTTP: Proxy Básico com Autenticação

O Net::HTTP é parte da biblioteca padrão do Ruby, tornando-o ideal para projetos que não podem adicionar dependências externas. A configuração de proxy é direta, mas requer atenção à autenticação e tratamento de erros.

Configuração Básica de Proxy

require 'net/http'
require 'uri'

# Configuração do proxy ProxyHat
PROXY_HOST = 'gate.proxyhat.com'
PROXY_PORT = 8080
PROXY_USER = 'seu_usuario'
PROXY_PASS = 'sua_senha'

def fetch_with_proxy(url, proxy_user: PROXY_USER, proxy_pass: PROXY_PASS)
  uri = URI.parse(url)
  
  # Cria conexão HTTP através do proxy
  http = Net::HTTP.new(uri.host, uri.port, PROXY_HOST, PROXY_PORT, proxy_user, proxy_pass)
  
  # Configuração TLS/SSL
  http.use_ssl = uri.scheme == 'https'
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.open_timeout = 15
  http.read_timeout = 30
  
  # Constrói a requisição
  request = Net::HTTP::Get.new(uri.request_uri)
  request['User-Agent'] = 'ProxyHat-Ruby/1.0'
  request['Accept'] = 'text/html,application/json'
  
  # Executa com tratamento de erros
  response = http.request(request)
  
  case response
  when Net::HTTPSuccess
    { status: response.code.to_i, body: response.body, headers: response.each_header.to_h }
  when Net::HTTPRedirection
    fetch_with_proxy(response['location'], proxy_user: proxy_user, proxy_pass: proxy_pass)
  else
    raise "HTTP Error #{response.code}: #{response.message}"
  end
rescue Net::OpenTimeout => e
  raise "Timeout de conexão: #{e.message}"
rescue Net::ReadTimeout => e
  raise "Timeout de leitura: #{e.message}"
rescue SocketError => e
  raise "Erro de DNS/rede: #{e.message}"
rescue OpenSSL::SSL::SSLError => e
  raise "Erro SSL/TLS: #{e.message}"
ensure
  http&.finish if http&.started?
end

# Exemplo de uso
result = fetch_with_proxy('https://httpbin.org/ip')
puts "Status: #{result[:status]}"
puts "IP detectado: #{JSON.parse(result[:body])['origin']}"

Proxy com Sessão Persistente (Sticky Session)

Para manter o mesmo IP durante múltiplas requisições, use o flag de sessão no username do ProxyHat:

require 'net/http'
require 'uri'

class StickyProxySession
  def initialize(username, password, session_id)
    @proxy_host = 'gate.proxyhat.com'
    @proxy_port = 8080
    # Formato: usuario-session-SESSION_ID
    @proxy_user = "#{username}-session-#{session_id}"
    @proxy_pass = password
    @connections = {}
  end
  
  def get(url)
    uri = URI.parse(url)
    key = "#{uri.host}:#{uri.port}"
    
    # Reutiliza conexão existente ou cria nova
    http = @connections[key] ||= begin
      Net::HTTP.new(uri.host, uri.port, @proxy_host, @proxy_port, @proxy_user, @proxy_pass).tap do |h|
        h.use_ssl = uri.scheme == 'https'
        h.verify_mode = OpenSSL::SSL::VERIFY_PEER
        h.keep_alive_timeout = 60
        h.start
      end
    end
    
    request = Net::HTTP::Get.new(uri.request_uri)
    http.request(request)
  rescue Errno::ECONNRESET, IOError
    # Reconecta em caso de falha
    @connections.delete(key)
    retry
  end
  
  def close_all
    @connections.each_value(&:finish)
    @connections.clear
  end
end

# Uso: mesma sessão = mesmo IP
session = StickyProxySession.new('user', 'pass', 'order-12345')
begin
  5.times do |i|
    response = session.get('https://httpbin.org/ip')
    puts "Requisição #{i + 1}: #{response.body}"
  end
ensure
  session.close_all
end

Typhoeus: Requisições Paralelas com Hydra

O Typhoeus é um wrapper Ruby para libcurl, oferecendo performance superior e suporte nativo a requisições paralelas através do Hydra. É ideal para scraping em escala.

Configuração do Typhoeus com Proxy

require 'typhoeus'

# Configuração global do proxy (opcional)
Typhoeus.configure do |config|
  config.user_agent = 'ProxyHat-Typhoeus/2.0'
  config.verbose = false
end

def create_request(url, proxy_user: 'user', proxy_pass: 'pass', country: nil)
  # Geo-targeting via username
  username = country ? "#{proxy_user}-country-#{country}" : proxy_user
  proxy_url = "http://#{username}:#{proxy_pass}@gate.proxyhat.com:8080"
  
  Typhoeus::Request.new(
    url,
    method: :get,
    proxy: proxy_url,
    headers: {
      'Accept' => 'text/html,application/xhtml+xml,application/json',
      'Accept-Language' => 'pt-BR,pt;q=0.9,en;q=0.8'
    },
    timeout: 30,
    connecttimeout: 15,
    followlocation: true,
    ssl_verifypeer: true,
    ssl_verifyhost: 2
  )
end

# Requisição única com proxy
request = create_request('https://httpbin.org/ip', proxy_user: 'seu_user', proxy_pass: 'sua_pass')
response = request.run

if response.success?
  puts "Status: #{response.code}"
  puts "Body: #{response.body}"
elsif response.timed_out?
  puts "Timeout!"
elsif response.code == 0
  puts "Erro de conexão: #{response.return_message}"
else
  puts "HTTP #{response.code}: #{response.status_message}"
end

Hydra: Requisições Paralelas em Lote

require 'typhoeus'

class ParallelScraper
  def initialize(username, password, concurrency: 50)
    @username = username
    @password = password
    @concurrency = concurrency
    @results = Queue.new
  end
  
  def fetch_all(urls, country: nil)
    hydra = Typhoeus::Hydra.new(max_concurrency: @concurrency)
    
    urls.each_with_index do |url, index|
      request = build_request(url, country: country)
      
      request.on_complete do |response|
        @results << {
          index: index,
          url: url,
          status: response.code,
          body: response.body,
          total_time: response.total_time,
          success: response.success?
        }
      end
      
      hydra.queue(request)
    end
    
    # Executa todas as requisições
    hydra.run
    
    collect_results(urls.size)
  end
  
  private
  
  def build_request(url, country: nil)
    username = country ? "#{@username}-country-#{country}" : @username
    proxy_url = "http://#{username}:#{@password}@gate.proxyhat.com:8080"
    
    Typhoeus::Request.new(
      url,
      method: :get,
      proxy: proxy_url,
      timeout: 30,
      connecttimeout: 15,
      followlocation: true,
      ssl_verifypeer: true
    )
  end
  
  def collect_results(expected_count)
    results = []
    expected_count.times { results << @results.pop }
    results.sort_by { |r| r[:index] }
  end
end

# Exemplo: scraping de 100 URLs em paralelo
scraper = ParallelScraper.new('seu_user', 'sua_pass', concurrency: 25)

urls = 100.times.map { |i| "https://httpbin.org/delay/#{rand(1..3)}" }
results = scraper.fetch_all(urls, country: 'US')

success_count = results.count { |r| r[:success] }
avg_time = results.sum { |r| r[:total_time] } / results.size

puts "Sucesso: #{success_count}/#{urls.size}"
puts "Tempo médio: #{'%.2f' % avg_time}s"

ProxyHat SDK: Rotação Automática e Geo-Targeting

O ProxyHat SDK encapsula a lógica de rotação de IPs, geo-targeting e tratamento de erros, permitindo focar na lógica de negócio.

require 'net/http'
require 'json'

module ProxyHat
  class Client
    GATEWAY_HOST = 'gate.proxyhat.com'
    GATEWAY_PORT = 8080
    
    attr_reader :username, :password
    
    def initialize(username:, password:, session: nil, country: nil, city: nil)
      @username = build_username(username, session: session, country: country, city: city)
      @password = password
      @retry_count = 0
      @max_retries = 3
    end
    
    def get(url, headers: {})
      request_with_retry(:get, url, headers: headers)
    end
    
    def post(url, body:, headers: {})
      request_with_retry(:post, url, body: body, headers: headers)
    end
    
    def rotate!
      @session_id = SecureRandom.hex(8)
      self
    end
    
    private
    
    def build_username(base, session: nil, country: nil, city: nil)
      parts = [base]
      parts << "session-#{session || SecureRandom.hex(8)}"
      parts << "country-#{country}" if country
      parts << "city-#{city}" if city
      parts.join('-')
    end
    
    def request_with_retry(method, url, body: nil, headers: {})
      uri = URI.parse(url)
      
      http = Net::HTTP.new(uri.host, uri.port, GATEWAY_HOST, GATEWAY_PORT, @username, @password)
      http.use_ssl = uri.scheme == 'https'
      http.verify_mode = OpenSSL::SSL::VERIFY_PEER
      http.open_timeout = 15
      http.read_timeout = 30
      
      request = build_request(method, uri, body, headers)
      response = http.request(request)
      
      handle_response(response, method, url, body, headers)
    rescue Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNRESET => e
      @retry_count += 1
      raise e if @retry_count > @max_retries
      
      sleep(2 ** @retry_count)
      rotate!
      retry
    ensure
      http&.finish if http&.started?
    end
    
    def build_request(method, uri, body, headers)
      klass = method == :get ? Net::HTTP::Get : Net::HTTP::Post
      request = klass.new(uri.request_uri)
      
      headers.each { |k, v| request[k] = v }
      request['User-Agent'] ||= 'ProxyHat-SDK/1.0'
      request.body = body.to_json if body && method == :post
      
      request
    end
    
    def handle_response(response, *retry_args)
      case response
      when Net::HTTPSuccess
        { status: response.code.to_i, body: response.body, headers: response.each_header.to_h }
      when Net::HTTPTooManyRequests
        @retry_count += 1
        raise 'Max retries exceeded' if @retry_count > @max_retries
        sleep(response['Retry-After']&.to_i || 60)
        request_with_retry(*retry_args)
      when Net::HTTPRedirection
        request_with_retry(:get, response['location'])
      else
        raise "HTTP #{response.code}: #{response.message}"
      end
    end
  end
  
  # Pool para múltiplas sessões
  class ProxyPool
    def initialize(username:, password:, pool_size: 10, country: nil)
      @clients = pool_size.times.map do |i|
        Client.new(
          username: username,
          password: password,
          session: "pool-#{i}-#{SecureRandom.hex(4)}",
          country: country
        )
      end
      @mutex = Mutex.new
      @index = 0
    end
    
    def with_client
      client = @mutex.synchronize do
        @index = (@index + 1) % @clients.size
        @clients[@index]
      end
      yield client
    end
  end
end

# Uso do SDK
client = ProxyHat::Client.new(
  username: 'seu_usuario',
  password: 'sua_senha',
  country: 'BR',
  city: 'sao-paulo'
)

result = client.get('https://httpbin.org/ip')
puts "IP brasileiro: #{JSON.parse(result[:body])['origin']}"

# Rotação manual
client.rotate!
result = client.get('https://httpbin.org/ip')
puts "Novo IP: #{JSON.parse(result[:body])['origin']}"

Scraping em Escala: 1000 URLs com Proxies Rotativos

Para scraping de larga escala, combinamos Typhoeus Hydra com o pool de proxies do ProxyHat, implementando circuit breaker e logging estruturado.

require 'typhoeus'
require 'json'
require 'logger'

module ProxyHat
  class ScalableScraper
    def initialize(username:, password:, concurrency: 100, country: 'US')
      @username = username
      @password = password
      @concurrency = concurrency
      @country = country
      @logger = Logger.new($stdout).tap { |l| l.level = Logger::INFO }
      @stats = { success: 0, failed: 0, retries: 0 }
      @stats_mutex = Mutex.new
    end
    
    def scrape(urls)
      @start_time = Time.now
      results = Concurrent::Array.new
      hydra = Typhoeus::Hydra.new(max_concurrency: @concurrency)
      
      urls.each_with_index do |url, idx|
        request = build_rotating_request(url, idx)
        
        request.on_complete do |response|
          result = process_response(response, url, idx)
          results << result
          update_stats(result)
        end
        
        hydra.queue(request)
      end
      
      hydra.run
      log_summary(results.size)
      results
    end
    
    private
    
    def build_rotating_request(url, index)
      # Cada requisição usa um IP diferente (rotação por requisição)
      session_id = "req-#{index}-#{SecureRandom.hex(4)}"
      username = "#{@username}-country-#{@country}-session-#{session_id}"
      proxy_url = "http://#{username}:#{@password}@gate.proxyhat.com:8080"
      
      Typhoeus::Request.new(
        url,
        method: :get,
        proxy: proxy_url,
        timeout: 45,
        connecttimeout: 20,
        followlocation: true,
        ssl_verifypeer: true,
        headers: {
          'User-Agent' => random_user_agent,
          'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
          'Accept-Language' => 'en-US,en;q=0.9',
          'Accept-Encoding' => 'gzip, deflate'
        }
      )
    end
    
    def process_response(response, url, index)
      {
        index: index,
        url: url,
        status: response.code,
        success: response.success?,
        body: response.body,
        time: response.total_time,
        ip: extract_ip_from_proxy(response),
        error: response.success? ? nil : response.return_message
      }
    end
    
    def update_stats(result)
      @stats_mutex.synchronize do
        if result[:success]
          @stats[:success] += 1
        else
          @stats[:failed] += 1
        end
      end
    end
    
    def extract_ip_from_proxy(response)
      # Alguns proxies retornam o IP no header X-Proxy-IP
      response.headers['X-Proxy-IP'] || 'unknown'
    rescue
      'unknown'
    end
    
    def random_user_agent
      agents = [
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
      ]
      agents.sample
    end
    
    def log_summary(total)
      elapsed = Time.now - @start_time
      rate = total / elapsed
      
      @logger.info("=" * 50)
      @logger.info("Scraping completo!")
      @logger.info("Total: #{total} URLs")
      @logger.info("Sucesso: #{@stats[:success]} | Falhas: #{@stats[:failed]}")
      @logger.info("Tempo: #{'%.2f' % elapsed}s")
      @logger.info("Taxa: #{'%.2f' % rate} req/s")
      @logger.info("=" * 50)
    end
  end
end

# Execução do scraper em escala
scraper = ProxyHat::ScalableScraper.new(
  username: 'seu_usuario',
  password: 'sua_senha',
  concurrency: 100,
  country: 'US'
)

# Gera 1000 URLs de exemplo
urls = 1000.times.map { |i| "https://httpbin.org/delay/#{rand(1..2)}?id=#{i}" }

results = scraper.scrape(urls)

# Exporta resultados bem-sucedidos
successful = results.select { |r| r[:success] }
puts "\nExportados #{successful.size} resultados válidos"

Configuração TLS/SSL: Certificados Self-Signed e SNI

Ao usar proxies, você pode encontrar servidores com certificados self-signed ou necessitar de configuração SNI (Server Name Indication) específica.

require 'net/http'
require 'openssl'

module ProxyHat
  class TLSClient
    def initialize(username:, password:, verify_mode: :peer)
      @username = username
      @password = password
      @verify_mode = verify_mode
      @ca_bundle = ENV.fetch('SSL_CERT_FILE', nil)
    end
    
    def get(url, sni_hostname: nil, allow_self_signed: false)
      uri = URI.parse(url)
      proxy_url = "http://#{@username}:#{@password}@gate.proxyhat.com:8080"
      
      http = Net::HTTP.new(uri.host, uri.port, 'gate.proxyhat.com', 8080, @username, @password)
      http.use_ssl = uri.scheme == 'https'
      
      # Configuração SSL/TLS
      configure_ssl(http, allow_self_signed)
      
      # SNI customizado (útil para hosts virtuais)
      if sni_hostname
        http.enable_post_connection_check = false
      end
      
      request = Net::HTTP::Get.new(uri.request_uri)
      request['Host'] = sni_hostname if sni_hostname
      
      response = http.request(request)
      
      { status: response.code.to_i, body: response.body }
    rescue OpenSSL::SSL::SSLError => e
      handle_ssl_error(e, url)
    ensure
      http&.finish if http&.started?
    end
    
    private
    
    def configure_ssl(http, allow_self_signed)
      case @verify_mode
      when :none
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      when :peer
        http.verify_mode = OpenSSL::SSL::VERIFY_PEER
        http.ca_file = @ca_bundle if @ca_bundle
      when :fail_if_no_peer_cert
        http.verify_mode = OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
      end
      
      # Permite certificados self-signed (APENAS em desenvolvimento!)
      if allow_self_signed
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
        warn '[AVISO] Verificação SSL desabilitada - não use em produção!'
      end
      
      # Configura versões TLS
      http.min_version = OpenSSL::SSL::TLS1_2_VERSION
      http.max_version = OpenSSL::SSL::TLS1_3_VERSION
      
      # Cipher suites seguros
      http.ciphers = 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
    end
    
    def handle_ssl_error(error, url)
      case error.message
      when /certificate verify failed/
        raise "Certificado inválido para #{url}. Verifique a CA ou use allow_self_signed: true (dev only)"
      when /hostname does not match/
        raise "Hostname mismatch. Use sni_hostname para especificar o hostname correto"
      when /handshake failure/
        raise "Falha no handshake TLS. Verifique versões/ciphers suportados"
      else
        raise "Erro SSL: #{error.message}"
      end
    end
  end
end

# Exemplo com configurações TLS
client = ProxyHat::TLSClient.new(
  username: 'seu_usuario',
  password: 'sua_senha',
  verify_mode: :peer
)

# Requisição normal
result = client.get('https://httpbin.org/get')
puts "Status: #{result[:status]}"

# Com SNI customizado (para CDNs/load balancers)
result = client.get('https://example.com/api', sni_hostname: 'api.example.com')

Integração com Rails: Faraday Middleware e ActiveJob

Em aplicações Rails, a integração de proxies é mais elegante usando Faraday como cliente HTTP e ActiveJob para processamento assíncrono.

Middleware Faraday para Proxy

# config/initializers/proxy_hat.rb
require 'faraday'
require 'faraday/retry'

module ProxyHat
  class FaradayMiddleware < Faraday::Middleware
    def initialize(app, username:, password:, country: nil, rotate: true)
      super(app)
      @username = username
      @password = password
      @country = country
      @rotate = rotate
    end
    
    def call(env)
      # Adiciona configuração de proxy à requisição
      env[:proxy] = build_proxy_config
      
      # Retry automático em caso de falha de proxy
      retries = 0
      max_retries = 3
      
      begin
        @app.call(env)
      rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
        retries += 1
        raise e if retries > max_retries
        
        Rails.logger.warn "Proxy falhou, tentando novo IP (tentativa #{retries})"
        env[:proxy] = build_proxy_config(force_new_ip: true)
        retry
      end
    end
    
    private
    
    def build_proxy_config(force_new_ip: false)
      session = @rotate ? SecureRandom.hex(8) : 'fixed-session'
      username = "#{@username}-country-#{@country}-session-#{session}"
      
      {
        uri: 'http://gate.proxyhat.com:8080',
        user: username,
        password: @password
      }
    end
  end
end

# Configuração do Faraday
Rails.application.config.faraday_proxy_client = Faraday.new do |f|
  f.use ProxyHat::FaradayMiddleware,
        username: ENV['PROXYHAT_USERNAME'],
        password: ENV['PROXYHAT_PASSWORD'],
        country: 'US',
        rotate: true
  
  f.request :retry, {
    max: 3,
    interval: 1.0,
    backoff_factor: 2,
    retry_statuses: [429, 500, 502, 503, 504]
  }
  
  f.response :json
  f.adapter :net_http_persistent
end

# app/services/scraper_service.rb
class ScraperService
  def initialize
    @client = Rails.application.config.faraday_proxy_client
  end
  
  def fetch(url)
    response = @client.get(url)
    response.body
  rescue Faraday::Error => e
    Rails.logger.error "Erro ao buscar #{url}: #{e.message}"
    nil
  end
end

ActiveJob para Scraping em Background

# app/jobs/scraping_job.rb
class ScrapingJob < ApplicationJob
  queue_as :scraping
  
  # Evita duplicatas
  sidekiq_options lock: :until_executed, lock_ttl: 3600 if defined?(Sidekiq)
  
  def perform(urls, options = {})
    @country = options.fetch(:country, 'US')
    @concurrency = options.fetch(:concurrency, 50)
    @batch_size = options.fetch(:batch_size, 100)
    
    results = []
    
    urls.each_slice(@batch_size) do |batch|
      batch_results = process_batch(batch)
      results.concat(batch_results)
      
      # Atualiza progresso
      update_progress(batch.size)
    end
    
    store_results(results)
    notify_completion(results.size)
  end
  
  private
  
  def process_batch(urls)
    hydra = Typhoeus::Hydra.new(max_concurrency: @concurrency)
    results = Concurrent::Array.new
    
    urls.each_with_index do |url, idx|
      request = build_request(url, idx)
      
      request.on_complete do |response|
        results << {
          url: url,
          status: response.code,
          body: response.body,
          success: response.success?
        }
      end
      
      hydra.queue(request)
    end
    
    hydra.run
    results
  end
  
  def build_request(url, index)
    session = "job-#{job_id}-req-#{index}"
    username = "#{ENV['PROXYHAT_USERNAME']}-country-#{@country}-session-#{session}"
    proxy_url = "http://#{username}:#{ENV['PROXYHAT_PASSWORD']}@gate.proxyhat.com:8080"
    
    Typhoeus::Request.new(
      url,
      method: :get,
      proxy: proxy_url,
      timeout: 30,
      connecttimeout: 15,
      followlocation: true,
      ssl_verifypeer: true
    )
  end
  
  def update_progress(count)
    # Atualiza cache/Redis com progresso
    Rails.cache.increment("scraping:#{job_id}:processed", count)
  end
  
  def store_results(results)
    # Bulk insert no banco
    ScrapedPage.insert_all(
      results.select { |r| r[:success] }.map do |r|
        {
          url: r[:url],
          content: r[:body],
          scraped_at: Time.current,
          job_id: job_id
        }
      end
    )
  end
  
  def notify_completion(count)
    ScrapingChannel.broadcast_to(
      'notifications',
      { event: 'scraping_complete', job_id: job_id, pages: count }
    )
  end
end

# Uso: enfileira scraping de 1000 URLs
ScrapingJob.perform_later(
  1000.times.map { |i| "https://example.com/page/#{i}" },
  country: 'BR',
  concurrency: 100
)

Comparação: Net::HTTP vs Typhoeus vs ProxyHat SDK

Característica Net::HTTP Typhoeus ProxyHat SDK
Dependências Stdlib (nenhuma) gem typhoeus, libcurl Net::HTTP wrapper
Requisições Paralelas Manual (threads) Nativo (Hydra) Manual (threads)
Performance Moderada Alta (libcurl) Moderada
Rotação de IP Manual Manual Automática
Geo-Targeting Manual Manual Integrado
Retry/Circuit Breaker Implementar Parcial Integrado
Ideal para Scripts simples, sem deps Scraping em escala Produção rápida

Pontos-Chave

  • Net::HTTP é suficiente para projetos simples sem dependências externas, mas requer mais código para paralelismo.
  • Typhoeus com Hydra é a melhor escolha para scraping em escala, oferecendo requisições paralelas nativas.
  • ProxyHat suporta rotação por requisição (sem session) ou sticky sessions (com session ID no username).
  • Geo-targeting é configurado via username: user-country-BR-city-sao-paulo.
  • TLS/SSL requer atenção especial ao usar proxies — configure verify_mode e versões TLS explicitamente.
  • Rails integration via Faraday middleware e ActiveJob permite scraping robusto em background.

Para projetos de scraping em produção, recomendamos Typhoeus para alta performance ou o ProxyHat SDK para desenvolvimento rápido com rotação automática. Confira nossos casos de uso de web scraping para mais exemplos práticos.

Pronto para começar?

Acesse mais de 50M de IPs residenciais em mais de 148 países com filtragem por IA.

Ver preçosProxies residenciais
← Voltar ao Blog