خانه/مقالات/اسکریپینگ با HTTPX و چرخش پراکسی‌ها
برنامه نویسی
پروکسی و چرخش IP
برگشت به مقاله‌ها

اسکریپینگ با HTTPX و چرخش پراکسی‌ها

اسکریپینگ با HTTPX و چرخش پراکسی‌ها
راهنمای جامع ترکیب پراکسی‌ها با HTTPX در پایتون: از روش پایهٔ پراکسی‌دهی و احراز هویت تا مسیردهی پیشرفته و سه فرمت رایج (لیست آی‌پی، دروازه و API)، همراه با مثال‌های کد، نکات امنیتی و بهترین روش‌ها برای پایداری و مانیتورینگ در اسکریپینگ.
آسان اسکریپ آسان اسکریپ
1405-05-10

مقدمه

در این مقاله قدم‌به‌قدم یاد می‌گیریم چگونه با HTTPX در پایتون از پراکسی‌ها استفاده کنیم، آن‌ها را احراز هویت کنیم، مسیر‌دهی (routing) بسازیم و سه فرمت رایج پراکسی (لیست آی‌پی، دروازه/گیت‌وی و API) را در اسکریپرهای خود ادغام کنیم. هدف این است که پس از مطالعه توانایی طراحی استراتژی چرخش پراکسی، مدیریت خطا و حفظ پایداری در کار با چندین آی‌پی را داشته باشید.

استفاده از آدرس‌های پراکسی با HTTPX

ایده کلی: ساختن یک دیکشنری از پراکسی‌ها و پاس دادن آن به درخواست‌های HTTPX. این روش برای درخواست‌های همگام (sync) و تمام متدهای HTTP قابل‌استفاده است.

مثال ساده (همگام):

import httpx

proxies = {
    "http://": "http://proxy.example.com:8080",
    "https://": "http://proxy.example.com:8081",
}

response = httpx.get('http://example.com', proxies=proxies)
print(response.status_code)

توضیح خط‌به‌خط:

  • وارد کردن کتابخانه httpx.
  • تعریف دیکشنری proxies که کلیدها نشان‌دهندهٔ scheme هستند و مقدارها URL پراکسی.
  • پاس دادن proxies به فراخوانی httpx.get که باعث می‌شود درخواست از طریق پراکسی ارسال شود.

نکته عملی: این روش برای متدهای GET, POST, PUT و سایر متدها کار می‌کند.

احراز هویت پراکسی

اگر پراکسی نیاز به username و password داشته باشد، آن‌ها را در خود URL پراکسی قرار می‌دهیم. اما هرگز Credential را هاردکُد نکنید؛ از متغیرهای محیطی یا vault استفاده کنید.

import os
import httpx

proxy_user = os.getenv('PROXY_USER')
proxy_pass = os.getenv('PROXY_PASS')
proxy_host = 'proxy.example.com:8080'

proxies = {
    'http://': f'http://{proxy_user}:{proxy_pass}@{proxy_host}',
    'https://': f'http://{proxy_user}:{proxy_pass}@{proxy_host}',
}

r = httpx.get('https://example.com', proxies=proxies)
print(r.status_code)

نکات امنیتی و عملی:

  • از متغیرهای محیطی برای نگهداری USERNAME و PASSWORD استفاده کنید.
  • اگر کلیدها و رمزها را در لاگ‌ها نمی‌خواهید، قبل از لاگ‌کردن طول یا دامنهٔ مقدار را ماسک کنید.

مسیردهی پراکسی (Proxy Routing)

HTTPX به شما امکان می‌دهد تا مشخص کنید کدام درخواست از کدام پراکسی عبور کند: می‌توانید براساس scheme، دامنه، پورت یا ترکیبی از این‌ها مسیردهی کنید. تطبیق از جزئی‌ترین (مثل https://domain:port) به کلی‌ترین انجام می‌شود.

مثال‌ها:

Wildcard - ارسال همهٔ درخواست‌ها از یک پراکسی:

proxies = {
    'all://': 'http://85.237.57.198:20000',
}

Scheme routing - استفاده از پراکسی‌های متفاوت برای HTTP و HTTPS:

proxies = {
    'http://': 'http://85.237.57.198:20000',
    'https://': 'http://85.237.57.198:20001',
}

Domain routing - کنترل پراکسی براساس دامنه (مثال: دور زدن پراکسی برای برخی سایت‌ها):

proxies = {
    'all://*target.com': 'none',  # هیچ پراکسی برای target.com
    'all://*walmart.com': 'http://USERNAME:PASSWORD@zproxy.example:22225',
    'all://': 'http://scraperapi:APIKEY@proxy-server:8001',
}

نکات عملی:

  • عبارت 'none' برای عبور مستقیم بدون پراکسی کاربرد دارد.
  • الگویابی دقیق نیازمند درک ترتیب تطبیق است؛ ابتدا قوانین خاص‌تر بررسی می‌شوند.
  • برای جلوگیری از لو رفتن credentialها، سعی کنید از توکن‌ها یا دروازه‌هایی استفاده کنید که نیاز به افشای اطلاعات سرور نداشته باشند.

استفاده از Client (جلسهٔ HTTPX)

وقتی از httpx.Client() استفاده می‌کنید، معمولاً پراکسی را موقع ساختن Client می‌دهید تا از connection pooling و reuse بهره‌مند شوید. توجه داشته باشید که اگر از یک پراکسی ثابت برای همهٔ درخواست‌ها استفاده کنید، هر درخواست از همان آی‌پی خواهد رفت و احتمال بلاک شدن افزایش می‌یابد.

import httpx

proxies = {
    'http://': 'http://USERNAME:PASSWORD@proxy.example.com:8080',
    'https://': 'http://USERNAME:PASSWORD@proxy.example.com:8080',
}

with httpx.Client(proxies=proxies) as client:
    r = client.get('https://httpbin.org/ip')
    print(r.text)

نکات مهم:

  • ایجاد Client هزینهٔ اتصال اولیه دارد اما برای تعداد زیادی درخواست موازی با یک پراکسی مفید است.
  • اگر می‌خواهید پراکسی را برای هر درخواست تغییر دهید، بهتر است پراکسی را در سطح درخواست تنظیم کنید یا از یک دروازه/گیت‌وی استفاده کنید که خودش چرخش انجام می‌دهد.
  • در صورت نیاز به همزمانی بالا، از AsyncClient و کنترل کننده‌هایی مانند semaphore برای محدود کردن اتصال همزمان استفاده کنید.

سه فرمت رایج پراکسی — مقایسه و مزایا/معایب

  • چرخش از لیست آی‌پی‌ها
    • مزایا: کنترل کامل روی انتخاب آی‌پی و رفتار چرخش.
    • معایب: نیاز به نگهداری، نظارت و حذف آی‌پی‌های مسدود شده؛ پیاده‌سازی پیچیده‌تر در مقیاس.
  • دروازه/Proxy Gateway
    • مزایا: یک نقطهٔ اتصال ساده؛ ارائه‌دهنده مسئول چرخش و تمیزسازی است.
    • معایب: وابستگی به ارائه‌دهنده و ممکن است هزینهٔ بالاتر.
  • API پراکسی
    • مزایا: ارسال URL به API و دریافت HTML، مدیریت هدرها، چرخش و برخی اوقات ریدرکت‌ها توسط API انجام می‌شود.
    • معایب: کاهش کنترل محلی؛ ممکن است محدودیت‌های نرخ یا قالب پاسخ خاص داشته باشد.

پراکسی‌سازی نوع اول: چرخش از لیست آی‌پی‌ها

رویکرد: ارائه‌دهنده لیستی از پراکسی‌ها می‌دهد و ما باید در کد یک مکانیزم برای انتخاب و مدیریت آن‌ها بسازیم.

import random
import httpx
import time

proxy_list = [
    'http://User:Pass@85.237.57.198:20000',
    'http://User:Pass@85.237.57.198:21000',
    'http://User:Pass@85.237.57.198:22000',
]

def fetch(url, timeout=10):
    proxy = random.choice(proxy_list)
    proxies = {'http://': proxy, 'https://': proxy}
    try:
        r = httpx.get(url, proxies=proxies, timeout=timeout)
        return r.status_code, r.text
    except httpx.HTTPError as e:
        # مدیریت خطا: لاگ کردن، حذف پراکسی بد، یا retry با backoff
        print('Request failed:', e)
        return None, None

if __name__ == '__main__':
    status, body = fetch('https://example.com')
    if status:
        print('OK', status)

توضیحات و توسعهٔ ایده:

  • ورودی تابع fetch، آدرس هدف و timeout است؛ خروجی کد وضعیت HTTP و متن پاسخ است.
  • در عمل باید یک مکانیسم مانیتورینگ برای سنجش نرخ خطا/زمان پاسخ هر آی‌پی بسازید و پراکسی‌های بد را موقتاً یا دائماً حذف کنید.
  • استفاده از exponential backoff، محدود کردن نرخ درخواست به هر پراکسی و تست سلامت پراکسی‌ها (health check) ضروری است.

پراکسی‌سازی نوع دوم: دروازهٔ پراکسی (Proxy Gateway)

ایده: به جای مدیریت لیست پراکسی، فقط یک پراکسی (یا چند دروازه) را پیکربندی می‌کنیم و ارائه‌دهنده وظیفهٔ چرخش، انتخاب و تمیزسازی را بر عهده دارد. این روش معمولاً برای پراکسی‌های residential یا mobile به‌صرفه است.

import httpx

proxies = {
    'http://': 'http://USERNAME:PASSWORD@gateway.proxyprovider.com:22225',
    'https://': 'http://USERNAME:PASSWORD@gateway.proxyprovider.com:22225',
}

r = httpx.get('https://example.com', proxies=proxies)
print(r.status_code)

نکات عملی:

  • سادگی ادغام: شما دیگر لیست پراکسی‌ها را مدیریت نمی‌کنید.
  • پایداری بهتر در برخی موارد اما وابستگی به کیفیت سرویس‌دهنده.

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

ایده: به یک API درخواست می‌فرستیم که خودش URL مقصد را دریافت می‌کند و پاسخ HTML را برمی‌گرداند. این راهکار اغلب برای ساده‌سازی و مقابله با محافظت‌های پیچیده مفید است.

import httpx

api_endpoint = 'https://proxy.api/endpoint'
payload = {
    'api_key': 'APIKEY',
    'url': 'https://httpbin.org/ip',
}

# بهترین روش: ارسال پارامترها به عنوان dict تا httpx خودش آنها را encode کند
r = httpx.get(api_endpoint, params=payload, timeout=20)
print(r.status_code)
print(r.text)

نکات مهم دربارهٔ URL encoding:

  • استفاده از پارامتر params باعث می‌شود httpx به‌درستی URL-encode را مدیریت کند.
  • اگر نیاز به تولید دستی کوئری است، می‌توانید از urllib.parse.urlencode استفاده کنید، اما بهتر است params را به صورت dict نگه دارید.

نکات عملکردی، پایداری و امنیت

  • کنکشن پولینگ: از Client یا AsyncClient برای بهره‌وری بیشتر استفاده کنید تا هزینهٔ برقراری اتصال را کاهش دهید.
  • همزمانی: در حالت Async از محدودکننده‌هایی مثل semaphore استفاده کنید تا به سرویس هدف و پراکسی‌ها فشار زیاد وارد نشود.
  • ری‌تراِی و backoff: برای خطاهای موقتی (HTTP 429, timeouts) از الگوریتم‌هایی مثل exponential backoff بهره ببرید.
  • نظارت و متریک: لاگ زمان پاسخ، نرخ خطا و درصد پاسخ 200 برای هر پراکسی را ثبت کنید تا پراکسی‌های بد حذف شوند.
  • مدیریت احراز هویت: از متغیرهای محیطی، secret manager یا vault برای نگهداری credentialها استفاده کنید؛ آن‌ها را در لاگ‌ها چاپ نکنید.
  • هوشمندانه انتخاب کنید: برای اسکِیل بزرگ معمولاً استفاده از دروازه یا API پراکسی سریع‌تر و عملی‌تر است؛ برای کنترل دقیق‌تر از لیست آی‌پی استفاده کنید.

جمع‌بندی

در این راهنما با روش‌های مختلف ادغام پراکسی با HTTPX آشنا شدیم: استفادهٔ مستقیم از لیست آی‌پی و چرخش دستی، اتصال به دروازهٔ پراکسی و استفاده از API پراکسی. هر روش مزایا و معایب خودش را دارد؛ انتخاب درست بستگی به نیاز به کنترل، هزینه و میزان مقیاس شما دارد. در عمل ترکیب چندین تکنیک (مثلاً API پراکسی + لاگینگ و retries) به شما بیشترین پایداری را می‌دهد.

پیشنهاد عملی: برای شروع، یک پیاده‌سازی کوچک با Gateway یا API پراکسی ایجاد کنید، مانیتورینگ پایه را اضافه کنید و سپس در صورت نیاز به کنترل بیشتر به چرخش لیست آی‌پی‌ها و مانیتورینگ هر آی‌پی بپردازید.

مطالب مرتبط

مقاله‌های مرتبط