بازگشت به وبلاگ

تنظیم پروکسی در Ruby با استفاده از Net::HTTP و Faraday: راهنمای کامل برای Rails و اسکریپت‌های مستقل

چگونه پروکسی را در پروژه‌های Ruby از طریق Net::HTTP و Faraday به درستی تنظیم کنیم - با مثال‌هایی برای Rails و اسکریپت‌های مستقل، چرخش IP و دور زدن مسدودیت‌ها.

📅۲۲ مرداد ۱۴۰۵
```html

اگر شما یک پارسر می‌نویسید، یک API خارجی را ادغام می‌کنید یا جمع‌آوری داده‌ها را در Ruby خودکار می‌کنید — دیر یا زود با مسدودیت‌های IP مواجه خواهید شد. Wildberries، Ozon، Instagram و ده‌ها سرویس دیگر درخواست‌ها را از یک آدرس بعد از چند صد تماس قطع می‌کنند. راه‌حل یکی است — پروکسی. در این مقاله بررسی خواهیم کرد که چگونه پروکسی را به پروژه Ruby خود از طریق Net::HTTP استاندارد و HTTP-client محبوب Faraday متصل کنیم، چرخش IP را تنظیم کنیم و خطاها را به درستی مدیریت کنیم — هم در برنامه Rails و هم در اسکریپت‌های ساده.

چرا توسعه‌دهنده Ruby به پروکسی نیاز دارد: سناریوهای اصلی

Ruby به طور فعال برای وظایفی استفاده می‌شود که بدون پروکسی نمی‌توان از آن‌ها عبور کرد. قبل از اینکه به کد برویم، باید بفهمیم که در چه موقعیت‌هایی به آن‌ها نیاز داریم — این به انتخاب نوع و معماری مناسب کمک می‌کند.

پارسر و جمع‌آوری داده‌ها. این رایج‌ترین سناریو است. شما یک اسکریپت Ruby می‌نویسید که صفحات Wildberries، Ozon یا Avito را مرور می‌کند و قیمت‌ها و ویژگی‌های محصولات را جمع‌آوری می‌کند. بدون پروکسی، چنین اسکریپتی بعد از چند دقیقه به دلیل IP مسدود می‌شود. وب‌سایت‌ها صدها درخواست از یک آدرس را می‌بینند و به طور خودکار حفاظت را فعال می‌کنند — CAPTCHA، مسدودیت موقت یا عدم خدمات کامل.

ادغام با API‌های وابسته به جغرافیا. برخی از سرویس‌های خارجی محتواهای مختلفی را بسته به کشور درخواست‌کننده برمی‌گردانند. اگر برنامه Rails شما به چنین API‌ای مراجعه کند، پروکسی اجازه می‌دهد تا درخواست‌ها را از منطقه مورد نظر شبیه‌سازی کند. به عنوان مثال، بررسی نتایج موتورهای جستجو برای کشورهای مختلف یا دریافت قیمت‌های مربوط به بازار خاص.

تست و QA. توسعه‌دهندگان از پروکسی برای آزمایش رفتار برنامه در هنگام درخواست از IP‌های مختلف و کشورها استفاده می‌کنند. این به ویژه برای سرویس‌هایی که دارای مسدودیت جغرافیایی یا محدودیت نرخ بر اساس IP هستند، مهم است.

خودکارسازی بازاریابی. اسکریپت‌های Ruby اغلب برای نظارت بر کمپین‌های تبلیغاتی، بررسی موقعیت‌ها در نتایج یا پیگیری فعالیت‌های رقبای خود استفاده می‌شوند. در اینجا پروکسی برای توزیع بار و دور زدن محدودیت‌ها ضروری است.

کار با چندین حساب. اگر اسکریپت شما چندین حساب را در یک پلتفرم مدیریت می‌کند، هر حساب باید از یک IP جداگانه استفاده کند — در غیر این صورت پلتفرم به راحتی ارتباط را شناسایی کرده و همه را به طور همزمان مسدود می‌کند.

کدام نوع پروکسی را برای وظایف Ruby انتخاب کنیم

همه پروکسی‌ها به یک اندازه برای وظایف مختلف مناسب نیستند. انتخاب نوع به طور مستقیم بر موفقیت کار اسکریپت شما تأثیر می‌گذارد. بیایید گزینه‌های اصلی را در زمینه توسعه Ruby بررسی کنیم.

نوع پروکسی بهترین وظایف در Ruby سرعت دور زدن حفاظت‌ها
پروکسی‌های دیتاسنتر پارسر بدون حفاظت سخت، درخواست‌های API، تست بالا متوسط
پروکسی‌های مسکونی پارسر وب‌سایت‌های محافظت‌شده، کار با شبکه‌های اجتماعی، بازارها متوسط بالا
پروکسی‌های موبایل Facebook، Instagram، TikTok API، کار با حساب‌ها متوسط حداکثر

پروکسی‌های دیتاسنتر — سریع‌ترین و ارزان‌ترین گزینه هستند. برای پارس کردن وب‌سایت‌ها بدون حفاظت‌های تهاجمی، درخواست‌های API انبوه و تست بار مناسب هستند. با این حال، پلتفرم‌های بزرگ (Facebook، Google، Cloudflare) به راحتی آن‌ها را بر اساس ASN دیتاسنتر شناسایی می‌کنند.

پروکسی‌های مسکونی از IP کاربران واقعی خانگی استفاده می‌کنند. برای اسکریپت‌های Ruby که Wildberries، Ozon را پارس می‌کنند یا با وب‌سایت‌های محافظت‌شده کار می‌کنند — این انتخاب بهینه است. وب‌سایت‌ها یک کاربر عادی را می‌بینند، نه یک سرور.

پروکسی‌های موبایل از IP اپراتورهای موبایل (4G/5G) استفاده می‌کنند. این آدرس‌ها از نظر پلتفرم‌ها معتبرترین هستند — یک IP موبایل می‌تواند به طور همزمان توسط صدها کاربر واقعی استفاده شود، بنابراین مسدودیت‌ها بر اساس آن بسیار نادر است. اگر اسکریپت Ruby شما با شبکه‌های اجتماعی یا پلتفرم‌های تبلیغاتی کار می‌کند — پروکسی‌های موبایل خطر مسدودیت‌ها را به حداقل می‌رسانند.

پروکسی در Net::HTTP: تنظیمات پایه

Net::HTTP — کتابخانه استاندارد Ruby برای درخواست‌های HTTP که در بسته استاندارد زبان گنجانده شده است. این کتابخانه به طور پیش‌فرض پروکسی را از طریق متد خاص Net::HTTP::Proxy پشتیبانی می‌کند.

ساده‌ترین راه — ایجاد یک کلاس پروکسی و استفاده از آن به جای Net::HTTP معمولی:

require 'net/http'
require 'uri'

# داده‌های پروکسی
proxy_host = 'proxy.example.com'
proxy_port = 8080

# ایجاد کلاس پروکسی
proxy_class = Net::HTTP::Proxy(proxy_host, proxy_port)

# انجام درخواست از طریق پروکسی
uri = URI('https://httpbin.org/ip')

proxy_class.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
  request = Net::HTTP::Get.new(uri)
  response = http.request(request)
  puts response.body
end

متد Net::HTTP::Proxy چهار پارامتر می‌پذیرد: هاست پروکسی، پورت، نام کاربری و رمز عبور. دو پارامتر اول الزامی هستند، دو پارامتر آخر برای پروکسی بدون احراز هویت اختیاری هستند.

روش جایگزین — ارسال پارامترهای پروکسی به طور مستقیم به متد Net::HTTP.new:

require 'net/http'

uri = URI('https://httpbin.org/ip')

http = Net::HTTP.new(
  uri.host,
  uri.port,
  'proxy.example.com',  # proxy_addr
  8080,                  # proxy_port
  nil,                   # proxy_user (nil اگر بدون احراز هویت)
  nil                    # proxy_pass
)

http.use_ssl = true

response = http.get(uri.path)
puts response.body

این روش زمانی مناسب است که شما نیاز دارید از یک شیء HTTP یکسان برای چندین درخواست به یک هاست استفاده کنید. توجه داشته باشید: پارامترهای پروکسی به عنوان آرگومان‌های سوم و چهارم ارسال می‌شوند، نه از طریق یک متد جداگانه.

احراز هویت و HTTPS از طریق Net::HTTP

بیشتر پروکسی‌های تجاری نیاز به احراز هویت دارند — نام کاربری و رمز عبور. علاوه بر این، هنگام کار با وب‌سایت‌های HTTPS نیاز به تنظیمات اضافی SSL است. بیایید هر دو مورد را بررسی کنیم.

پروکسی با نام کاربری و رمز عبور:

require 'net/http'
require 'uri'

proxy_host = 'proxy.example.com'
proxy_port = 8080
proxy_user = 'your_username'
proxy_pass = 'your_password'

# ایجاد کلاس پروکسی با احراز هویت
proxy_class = Net::HTTP::Proxy(proxy_host, proxy_port, proxy_user, proxy_pass)

uri = URI('https://httpbin.org/ip')

proxy_class.start(uri.host, uri.port, use_ssl: true) do |http|
  # غیرفعال کردن تأیید SSL (فقط برای تست!)
  # http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  
  request = Net::HTTP::Get.new(uri)
  request['User-Agent'] = 'Mozilla/5.0 (compatible; MyBot/1.0)'
  
  response = http.request(request)
  puts "IP: #{response.body}"
  puts "Status: #{response.code}"
end

نکته مهم: هنگام استفاده از پروکسی HTTPS (تونل‌سازی از طریق CONNECT) Net::HTTP به طور خودکار یک اتصال SSL با سرور هدف از طریق تونل پروکسی برقرار می‌کند. این روش برای بیشتر پروکسی‌ها به درستی کار می‌کند.

تنظیم از طریق متغیرهای محیطی. یک روش خوب این است که داده‌های پروکسی را در کد هاردکد نکنید، بلکه آن‌ها را از متغیرهای محیطی بخوانید:

require 'net/http'
require 'uri'

# خواندن تنظیمات پروکسی از ENV
proxy_uri = URI(ENV.fetch('HTTP_PROXY', 'http://proxy.example.com:8080'))

proxy_class = Net::HTTP::Proxy(
  proxy_uri.host,
  proxy_uri.port,
  proxy_uri.user,
  proxy_uri.password
)

target_uri = URI('https://httpbin.org/ip')

proxy_class.start(target_uri.host, target_uri.port, use_ssl: true) do |http|
  response = http.get(target_uri.path)
  puts response.body
end

متغیر محیطی را می‌توان به صورت HTTP_PROXY=http://user:[email protected]:8080 تنظیم کرد. این روش اجازه می‌دهد تا پروکسی را بدون تغییر کد تغییر دهید — کافی است متغیر را در فایل .env یا در تنظیمات سرور به‌روزرسانی کنید.

اتصال پروکسی از طریق Faraday

Faraday — یکی از محبوب‌ترین HTTP-client‌ها در اکوسیستم Ruby است. این کتابخانه در بسیاری از برنامه‌های Rails به دلیل رویکرد راحت middleware و پشتیبانی از آداپتورهای مختلف (Net::HTTP، HTTParty، Typhoeus و غیره) استفاده می‌شود. تنظیم پروکسی در Faraday بسته به آداپتور مورد استفاده کمی متفاوت است.

تنظیم پایه پروکسی در Faraday:

require 'faraday'

# ایجاد اتصال Faraday با پروکسی
conn = Faraday.new(url: 'https://httpbin.org') do |faraday|
  faraday.proxy = {
    uri: 'http://proxy.example.com:8080',
    user: 'your_username',
    password: 'your_password'
  }
  
  faraday.headers['User-Agent'] = 'Mozilla/5.0 (compatible; MyBot/1.0)'
  faraday.adapter Faraday.default_adapter
end

response = conn.get('/ip')
puts response.body
puts "Status: #{response.status}"

پارامتر faraday.proxy یک هش با کلیدهای uri، user و password را می‌پذیرد. همچنین می‌توانید یک رشته URI را به طور مستقیم ارسال کنید، اگر پروکسی نیاز به احراز هویت نداشته باشد.

Faraday با آداپتور Net::HTTP و تنظیمات پیشرفته:

require 'faraday'

conn = Faraday.new(url: 'https://httpbin.org') do |faraday|
  faraday.proxy = 'http://user:[email protected]:8080'
  
  # تنظیمات تایم‌اوت
  faraday.options.timeout = 30
  faraday.options.open_timeout = 10
  
  # Middleware برای لاگ‌گذاری (مناسب برای دیباگ)
  faraday.response :logger
  
  # تلاش مجدد در صورت بروز خطاهای اتصال
  faraday.request :retry, max: 3, interval: 1
  
  # آداپتور
  faraday.adapter :net_http
end

begin
  response = conn.get('/ip')
  puts response.body
rescue Faraday::ConnectionFailed => e
  puts "خطای اتصال: #{e.message}"
rescue Faraday::TimeoutError => e
  puts "تایم‌اوت: #{e.message}"
end

Middleware :retry به ویژه هنگام کار با پروکسی مفید است — اگر یک آدرس به طور موقت در دسترس نباشد، Faraday به طور خودکار درخواست را تکرار می‌کند. این برای عملکرد مطمئن اسکریپت در تولید حیاتی است.

Faraday با آداپتور Typhoeus (برای درخواست‌های موازی):

# Gemfile: gem 'typhoeus'
require 'faraday'
require 'typhoeus/adapters/faraday'

conn = Faraday.new(url: 'https://httpbin.org') do |faraday|
  faraday.proxy = 'http://user:[email protected]:8080'
  faraday.adapter :typhoeus
end

# درخواست‌های موازی از طریق پروکسی
responses = []
conn.in_parallel do
  responses << conn.get('/ip')
  responses << conn.get('/headers')
  responses << conn.get('/user-agent')
end

responses.each { |r| puts r.body }

چرخش پروکسی: تغییر خودکار IP

یک آدرس پروکسی، حتی اگر مسکونی باشد، دیر یا زود تحت محدودیت‌ها قرار می‌گیرد هنگام پارس کردن شدید. راه‌حل — چرخش: تغییر خودکار IP بعد از هر درخواست یا از طریق فواصل مشخص. بیایید یک روتاتور ساده برای اسکریپت‌های Ruby پیاده‌سازی کنیم.

روتاتور ساده بر اساس آرایه پروکسی:

require 'net/http'
require 'uri'

class ProxyRotator
  def initialize(proxies)
    @proxies = proxies
    @index = 0
    @mutex = Mutex.new
  end

  def next_proxy
    @mutex.synchronize do
      proxy = @proxies[@index % @proxies.length]
      @index += 1
      proxy
    end
  end

  def random_proxy
    @proxies.sample
  end
end

# لیست پروکسی‌ها به فرمت [host, port, user, pass]
proxies = [
  ['proxy1.example.com', 8080, 'user1', 'pass1'],
  ['proxy2.example.com', 8080, 'user2', 'pass2'],
  ['proxy3.example.com', 8080, 'user3', 'pass3'],
]

rotator = ProxyRotator.new(proxies)

# پارس کردن لیست URL از طریق پروکسی‌های مختلف
urls = [
  'https://httpbin.org/ip',
  'https://httpbin.org/headers',
  'https://httpbin.org/user-agent'
]

urls.each do |url|
  proxy = rotator.next_proxy
  proxy_class = Net::HTTP::Proxy(proxy[0], proxy[1], proxy[2], proxy[3])
  
  uri = URI(url)
  
  begin
    proxy_class.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
      http.read_timeout = 15
      response = http.get(uri.path)
      puts "#{url} -> Status: #{response.code}, Proxy: #{proxy[0]}"
    end
  rescue => e
    puts "خطا با پروکسی #{proxy[0]}: #{e.message}"
    # به طور خودکار به پروکسی بعدی بروید
  end
  
  sleep(rand(0.5..2.0)) # تأخیر تصادفی بین درخواست‌ها
end

تأخیر تصادفی بین درخواست‌ها (sleep(rand(0.5..2.0))) — یک عنصر مهم است. الگوی درخواست‌ها با فواصل ثابت به راحتی توسط سیستم‌های ضد ربات شناسایی می‌شود. تأخیرهای تصادفی رفتار کاربر واقعی را شبیه‌سازی می‌کنند.

چرخش از طریق Faraday با middleware:

require 'faraday'

class ProxyMiddleware < Faraday::Middleware
  PROXIES = [
    'http://user1:[email protected]:8080',
    'http://user2:[email protected]:8080',
    'http://user3:[email protected]:8080',
  ].freeze

  def call(env)
    # انتخاب یک پروکسی تصادفی برای هر درخواست
    proxy_uri = URI(PROXIES.sample)
    
    env[:request][:proxy] = {
      uri: proxy_uri,
      user: proxy_uri.user,
      password: proxy_uri.password
    }
    
    @app.call(env)
  end
end

# ثبت middleware
Faraday::Middleware.register_middleware proxy_rotator: ProxyMiddleware

conn = Faraday.new(url: 'https://httpbin.org') do |faraday|
  faraday.use :proxy_rotator
  faraday.adapter :net_http
end

5.times do
  response = conn.get('/ip')
  puts response.body
end

ادغام پروکسی در برنامه Rails

در برنامه Rails، پروکسی بیشتر برای درخواست‌های HTTP خارجی نیاز است: ادغام با API، وظایف پس‌زمینه پارس یا وب‌هوک‌ها. چند الگوی عملی را بررسی کنیم.

الگوی 1: شیء سرویس با Faraday. یک کلاس سرویس پایه ایجاد کنید که تمام درخواست‌های HTTP خارجی را از طریق پروکسی انجام می‌دهد:

# app/services/http_client.rb
class HttpClient
  def self.connection(base_url)
    Faraday.new(url: base_url) do |faraday|
      # پروکسی از متغیرهای محیطی Rails
      if Rails.env.production? && ENV['PROXY_URL'].present?
        faraday.proxy = ENV['PROXY_URL']
      end
      
      faraday.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
      faraday.options.timeout = 30
      faraday.options.open_timeout = 10
      
      faraday.request :retry, max: 3, interval: 2,
                      exceptions: [Faraday::ConnectionFailed, Faraday::TimeoutError]
      
      faraday.response :raise_error
      faraday.adapter :net_http
    end
  end
end

# استفاده در کنترلر یا سرویس:
# client = HttpClient.connection('https://api.example.com')
# response = client.get('/products', { category: 'electronics' })

الگوی 2: تنظیم از طریق credentials Rails. برای ذخیره داده‌های پروکسی از credentials رمزگذاری شده Rails استفاده کنید:

# config/credentials.yml.enc (از طریق rails credentials:edit ویرایش می‌شود)
# proxy:
#   host: proxy.example.com
#   port: 8080
#   username: your_user
#   password: your_pass

# app/services/proxy_service.rb
class ProxyService
  def self.faraday_proxy_config
    creds = Rails.application.credentials.proxy
    return nil unless creds
    
    {
      uri: "http://#{creds[:host]}:#{creds[:port]}",
      user: creds[:username],
      password: creds[:password]
    }
  end
  
  def self.net_http_proxy
    creds = Rails.application.credentials.proxy
    return Net::HTTP::Proxy(nil, nil) unless creds
    
    Net::HTTP::Proxy(
      creds[:host],
      creds[:port],
      creds[:username],
      creds[:password]
    )
  end
end

الگوی 3: وظایف پس‌زمینه با Sidekiq. اگر پارس کردن یا درخواست‌های API در کارگران پس‌زمینه انجام می‌شود، تنظیم پروکسی همان‌طور که هست باقی می‌ماند، اما مهم است که رقابت را در نظر بگیرید:

# app/workers/price_parser_worker.rb
class PriceParserWorker
  include Sidekiq::Worker
  
  sidekiq_options retry: 3, queue: :parsers
  
  def perform(product_url)
    # ایجاد یک اتصال جدید برای هر کارگر
    proxy = ProxyService.net_http_proxy
    uri = URI(product_url)
    
    proxy.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
      http.read_timeout = 20
      
      request = Net::HTTP::Get.new(uri)
      request['User-Agent'] = random_user_agent
      
      response = http.request(request)
      
      if response.code == '200'
        parse_and_save(response.body, product_url)
      else
        Rails.logger.warn "وضعیت غیرمنتظره #{response.code} برای #{product_url}"
      end
    end
  rescue Net::OpenTimeout, Net::ReadTimeout => e
    Rails.logger.error "تایم‌اوت برای #{product_url}: #{e.message}"
    raise # Sidekiq وظیفه را تکرار خواهد کرد
  end
  
  private
  
  def random_user_agent
    agents = [
      'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
      'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
      'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
    ]
    agents.sample
  end
  
  def parse_and_save(html, url)
    # منطق پارس کردن...
  end
end

مدیریت خطاها و تایم‌اوت‌ها

کار کردن از طریق پروکسی یک لایه اضافی اضافه می‌کند که می‌تواند خطاهای خاصی تولید کند. مدیریت درست استثناها تفاوت بین یک اسکریپت است که بعد از 5 دقیقه سقوط می‌کند و یک اسکریپت است که ساعت‌ها بدون مداخله کار می‌کند.

انواع اصلی خطاها هنگام کار با پروکسی در Ruby:

استثنا دلیل چه کار کنیم
Net::OpenTimeout پروکسی پاسخ نمی‌دهد پروکسی را تغییر دهید، تکرار کنید
Net::ReadTimeout پروکسی کند است یا وب‌سایت پاسخ نمی‌دهد تایم‌اوت را افزایش دهید یا پروکسی را تغییر دهید
Errno::ECONNREFUSED پروکسی سرور اتصال را رد کرد داده‌های پروکسی را بررسی کنید
OpenSSL::SSL::SSLError مشکل با SSL از طریق پروکسی تنظیمات SSL را بررسی کنید
HTTP 407 نام کاربری/رمز عبور نادرست پروکسی مدارک را بررسی کنید
HTTP 403/429 IP توسط وب‌سایت مسدود شده است پروکسی را تغییر دهید، یک وقفه اضافه کنید

مدیریت جامع خطاها با تغییر خودکار پروکسی:

require 'net/http'
require 'uri'

class RobustHttpClient
  MAX_RETRIES = 3
  RETRIABLE_ERRORS = [
    Net::OpenTimeout,
    Net::ReadTimeout,
    Errno::ECONNREFUSED,
    Errno::ECONNRESET,
    OpenSSL::SSL::SSLError
  ].freeze

  def initialize(proxies)
    @proxies = proxies.dup
    @failed_proxies = []
  end

  def get(url, retries: MAX_RETRIES)
    uri = URI(url)
    attempt = 0

    begin
      attempt += 1
      proxy = current_proxy
      proxy_class = Net::HTTP::Proxy(*proxy)

      proxy_class.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
        http.open_timeout = 10
        http.read_timeout = 20

        request = Net::HTTP::Get.new(uri)
        request['User-Agent'] = 'Mozilla/5.0 (compatible; RubyBot/1.0)'

        response = http.request(request)

        case response.code.to_i
        when 200..299
          response
        when 407
          raise "احراز هویت پروکسی برای #{proxy[0]} ناموفق بود"
        when 403, 429
          rotate_proxy!
          raise "IP مسدود شده (#{response.code})، چرخش پروکسی"
        else
          raise "وضعیت HTTP غیرمنتظره: #{response.code}"
        end
      end

    rescue *RETRIABLE_ERRORS => e
      Rails.logger.warn "خطای اتصال (تلاش #{attempt}/#{retries}): #{e.message}"
      rotate_proxy!
      retry if attempt < retries
      raise "پس از #{retries} تلاش ناموفق: #{e.message}"

    rescue RuntimeError => e
      Rails.logger.warn "خطای HTTP (تلاش #{attempt}/#{retries}): #{e.message}"
      retry if attempt < retries
      raise
    end
  end

  private

  def current_proxy
    @proxies.first || raise("هیچ پروکسی در دسترس نیست!")
  end

  def rotate_proxy!
    failed = @proxies.shift
    @failed_proxies << failed
    Rails.logger.info "پروکسی چرخش یافت. باقی‌مانده: #{@proxies.length}"
  end
end

پروکسی SOCKS5 در Ruby: تنظیم از طریق socksify

Net::HTTP به طور بومی از SOCKS5 پشتیبانی نمی‌کند — فقط پروکسی‌های HTTP/HTTPS. برای کار با SOCKS5 به یک کتابخانه اضافی نیاز است. محبوب‌ترین گزینه — جواهر socksify است.

چرا SOCKS5 ممکن است بر HTTP-proxy ترجیح داده شود؟ پروتکل SOCKS5 در سطح پایین‌تری کار می‌کند — هر ترافیک TCP را پروکسی می‌کند، نه فقط HTTP. علاوه بر این، SOCKS5 از احراز هویت پشتیبانی می‌کند و متاداده‌های کمتری درباره درخواست را منتقل می‌کند، که آن را کمتر قابل شناسایی برای سیستم‌های شناسایی ربات‌ها می‌کند.

# Gemfile
# gem 'socksify'

require 'socksify'
require 'socksify/http'
require 'net/http'
require 'uri'

# تنظیمات جهانی پروکسی SOCKS5
TCPSocket::socks_server = 'proxy.example.com'
TCPSocket::socks_port = 1080

# اختیاری: احراز هویت (نام کاربری/رمز عبور SOCKS5)
# TCPSocket::socks_username = 'your_user'
# TCPSocket::socks_password = 'your_pass'

# حالا تمام درخواست‌های Net::HTTP از طریق SOCKS5 می‌روند
uri = URI('https://httpbin.org/ip')
response = Net::HTTP.get_response(uri)
puts response.body

توجه داشته باشید: هنگام استفاده از socksify تنظیمات به طور جهانی برای تمام اتصالات TCP در فرآیند اعمال می‌شود. اگر به تنظیمات انعطاف‌پذیرتری نیاز دارید — از Net::HTTP.SOCKSProxy از همان جواهر استفاده کنید:

require 'socksify/http'

# ایجاد کلاس پروکسی SOCKS5 (مشابه Net::HTTP::Proxy برای HTTP)
socks_proxy = Net::HTTP.SOCKSProxy('proxy.example.com', 1080)

uri = URI('https://httpbin.org/ip')

socks_proxy.start(uri.host, uri.port, use_ssl: true) do |http|
  response = http.get(uri.path)
  puts response.body
end

برای Faraday با SOCKS5 به یک آداپتور نیاز دارید که از این پروتکل پشتیبانی کند. گزینه خوبی faraday-net_http در ترکیب با socksify است، یا استفاده از آداپتور مبتنی بر curl faraday-typhoeus که به طور بومی از SOCKS5 از طریق libcurl پشتیبانی می‌کند.

💡 نکته‌ای در مورد انتخاب پروتکل

برای بیشتر وظایف پارس کردن و کار با API، پروکسی‌های HTTP/HTTPS کافی هستند — آن‌ها در تنظیمات ساده‌تر و به طور بومی پشتیبانی می‌شوند. SOCKS5 باید زمانی استفاده شود که شما نیاز به پروکسی کردن نه تنها ترافیک HTTP دارید، یا زمانی که پروکسی‌های HTTP به راحتی توسط سرویس هدف شناسایی می‌شوند. پروکسی‌های موبایل و مسکونی در هر دو پروتکل در دسترس هستند.

نتیجه‌گیری و توصیه‌ها

تنظیم پروکسی در Ruby نیاز به کتابخانه‌های پیچیده ندارد — Net::HTTP به طور پیش‌فرض از پروکسی‌های HTTP پشتیبانی می‌کند، و Faraday ادغام را به دلیل معماری middleware حتی راحت‌تر می‌کند. نکات کلیدی این راهنما:

  • برای Net::HTTP از Net::HTTP::Proxy استفاده کنید — این یک روش داخلی و قابل اعتماد است.
  • برای Faraday، پارامتر faraday.proxy یک رشته URI یا هش با مدارک را می‌پذیرد.
  • داده‌های پروکسی را در متغیرهای محیطی یا credentials Rails ذخیره کنید — در کد هاردکد نکنید.
  • چرخش پروکسی و مدیریت خطاها را برای عملکرد مطمئن در تولید پیاده‌سازی کنید.
  • تأخیرهای تصادفی و چرخش User-Agent را برای شبیه‌سازی رفتار انسانی اضافه کنید.
  • برای SOCKS5 از جواهر socksify استفاده کنید.

انتخاب نوع پروکسی به وظیفه بستگی دارد. اگر شما یک پارسر برای Wildberries یا Ozon می‌نویسید — پروکسی‌های مسکونی بهترین تعادل بین سرعت و دور زدن حفاظت‌ها را فراهم می‌کنند: IP‌های واقعی کاربران خانگی به ندرت در لیست‌های مسدود قرار می‌گیرند. برای وظایف با بار بالا و حجم بالای درخواست‌ها به منابع کمتر محافظت‌شده، پروکسی‌های دیتاسنتر مناسب‌تر هستند — آن‌ها سریع‌تر و ارزان‌تر در محاسبه بر اساس درخواست هستند. اگر اسکریپت Ruby شما با شبکه‌های اجتماعی یا API‌های تبلیغاتی کار می‌کند — به پروکسی‌های موبایل توجه کنید: آدرس‌های IP آن‌ها بالاترین سطح اعتماد را در بیشتر پلتفرم‌ها دارند.

```