Skip to content
Advanced / 4 min read

چگونه از پروکسی‌های مسکونی و دیتاسنتری Smartproxy با Scrapy در لینوکس استفاده کنیم

یک میان‌افزار دانلودر Scrapy بسازید که پروکسی‌های HTTP مسکونی و دیتاسنتری Smartproxy را در لینوکس می‌چرخاند، با اعتبارنامه‌های مبتنی بر محیط و تلاش‌های مجدد پشتیبان بین استخرها.

لینوکس HTTP(S) وب اسکرپینگ

مرور کلی

HttpProxyMiddleware داخلی Scrapy می‌تواند یک درخواست را از طریق یک پروکسی HTTP مسیریابی کند، اما خزش تولیدی با Smartproxy معمولاً به دو چیز نیاز دارد: یک استخر مسکونی برای درخواست‌های هدف‌گیری جغرافیایی یا مقاوم در برابر مسدودسازی، و یک استخر دیتاسنتری برای درخواست‌های پرحجم. این آموزش نشان می‌دهد چگونه یک میان‌افزار دانلودر سفارشی اضافه کنید که برای هر درخواست یک endpoint از Smartproxy انتخاب می‌کند، بین استخرهای مسکونی و دیتاسنتری می‌چرخد، و خطاهای رایج پروکسی را بدون هاردکد کردن اعتبارنامه‌ها در spider شما دوباره تلاش می‌کند.

Smartproxy از HTTP و SOCKS5 پشتیبانی می‌کند؛ این راهنما از endpointهای پروکسی HTTP/HTTPS استفاده می‌کند زیرا میان‌افزار پروکسی داخلی Scrapy انتظار URLهای پروکسی HTTP را دارد.

پیش‌نیازها

  • یک ماشین یا کانتینر لینوکسی با Python 3.10 یا جدیدتر.
  • یک حساب Smartproxy با اعتبارنامه‌های پروکسی مسکونی و/یا دیتاسنتری.
  • جزئیات endpoint از داشبورد Smartproxy: میزبان پروکسی، پورت، نام کاربری و رمز عبور برای هر استخری که قصد استفاده از آن را دارید.
  • pip و venv در دسترس باشند.

مراحل

مرحله ۱ — یک محیط مجازی ایجاد کنید و Scrapy را نصب کنید

python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install scrapy python-dotenv

مرحله ۲ — اعتبارنامه‌های Smartproxy را به عنوان متغیرهای محیطی ذخیره کنید

اعتبارنامه‌ها را در مخزن خود کامیت نکنید.

export SMARTPROXY_RES_HOST='your-residential-host'
export SMARTPROXY_RES_PORT='your-residential-port'
export SMARTPROXY_RES_USERNAME='your-residential-username'
export SMARTPROXY_RES_PASSWORD='your-residential-password'

export SMARTPROXY_DC_HOST='your-datacenter-host'
export SMARTPROXY_DC_PORT='your-datacenter-port'
export SMARTPROXY_DC_USERNAME='your-datacenter-username'
export SMARTPROXY_DC_PASSWORD='your-datacenter-password'

اگر فایل .env را ترجیح می‌دهید، آن را قبل از شروع Scrapy بارگذاری کنید. فایل را از کنترل نسخه خارج نگه دارید.

مرحله ۳ — پروژه Scrapy را ایجاد کنید

scrapy startproject smartproxy_scrapy
cd smartproxy_scrapy
scrapy genspider example example.com

مرحله ۴ — یک میان‌افزار چرخش Smartproxy اضافه کنید

فایل smartproxy_scrapy/middlewares.py را ایجاد کنید یا به فایل تولیدشده اضافه کنید. این میان‌افزار request.meta['proxy'] را قبل از اجرای HttpProxyMiddleware در Scrapy تنظیم می‌کند.

import os
from urllib.parse import quote

from scrapy import signals
from scrapy.exceptions import NotConfigured
from scrapy.utils.project import get_project_settings


class SmartproxyRotationMiddleware:
    '''Route Scrapy requests through Smartproxy residential or datacenter endpoints.'''

    def __init__(self, settings):
        self.pools = {
            'residential': {
                'host': settings.get('SMARTPROXY_RES_HOST'),
                'port': settings.get('SMARTPROXY_RES_PORT'),
                'username': settings.get('SMARTPROXY_RES_USERNAME'),
                'password': settings.get('SMARTPROXY_RES_PASSWORD'),
            },
            'datacenter': {
                'host': settings.get('SMARTPROXY_DC_HOST'),
                'port': settings.get('SMARTPROXY_DC_PORT'),
                'username': settings.get('SMARTPROXY_DC_USERNAME'),
                'password': settings.get('SMARTPROXY_DC_PASSWORD'),
            },
        }

        if not any(pool['host'] and pool['port'] for pool in self.pools.values()):
            raise NotConfigured('Set at least one Smartproxy pool host and port.')

    @classmethod
    def from_crawler(cls, crawler):
        middleware = cls(crawler.settings)
        crawler.signals.connect(middleware.spider_opened, signal=signals.spider_opened)
        return middleware

    def spider_opened(self, spider):
        spider.logger.info('Smartproxy rotation middleware enabled')

    def process_request(self, request, spider):
        pool_name = request.meta.get('proxy_pool', 'residential')
        pool = self.pools.get(pool_name)

        if not pool or not pool['host'] or not pool['port']:
            return None

        host = pool['host']
        port = pool['port']
        username = quote(pool['username'] or '', safe='')
        password = quote(pool['password'] or '', safe='')

        if username and password:
            proxy_url = f'http://{username}:{password}@{host}:{port}'
        else:
            proxy_url = f'http://{host}:{port}'

        request.meta['proxy'] = proxy_url
        request.meta['smartproxy_pool'] = pool_name
        return None

مرحله ۵ — میان‌افزار را قبل از میان‌افزار پروکسی Scrapy فعال کنید

فایل smartproxy_scrapy/settings.py را ویرایش کنید.

DOWNLOADER_MIDDLEWARES = {
    'smartproxy_scrapy.middlewares.SmartproxyRotationMiddleware': 749,
}

HTTPPROXY_ENABLED = True
DOWNLOAD_TIMEOUT = 30
RETRY_HTTP_CODES = [403, 407, 429, 500, 502, 503, 504]
RETRY_TIMES = 2
CONCURRENT_REQUESTS = 16
CONCURRENT_REQUESTS_PER_DOMAIN = 4

HttpProxyMiddleware داخلی Scrapy با ترتیب 750 قرار می‌گیرد، بنابراین 749 تضمین می‌کند که میان‌افزار شما ابتدا URL پروکسی را تنظیم کند.

مرحله ۶ — برای هر درخواست مسکونی یا دیتاسنتری را انتخاب کنید

از meta={'proxy_pool': 'residential'} برای صفحات هدف‌گیری جغرافیایی یا با ناشناسی بالا استفاده کنید. از meta={'proxy_pool': 'datacenter'} برای صفحات پرحجم و پایدار استفاده کنید.

import scrapy


class SmartproxyDemoSpider(scrapy.Spider):
    name = 'smartproxy_demo'
    start_urls = ['https://httpbin.org/ip']

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(
                url,
                meta={'proxy_pool': 'residential'},
                callback=self.parse,
                dont_filter=True,
            )
            yield scrapy.Request(
                url,
                meta={'proxy_pool': 'datacenter'},
                callback=self.parse,
                dont_filter=True,
            )

    def parse(self, response):
        yield {
            'pool': response.meta.get('smartproxy_pool'),
            'status': response.status,
            'origin': response.text.strip(),
        }

مرحله ۷ — تلاش‌های مجدد پشتیبان بین استخرها اضافه کنید

کد 403 یا 429 از سایت هدف اغلب به این معنی است که IP فعلی مسدود شده است. این متد را داخل کلاس SmartproxyRotationMiddleware اضافه کنید تا یک درخواست ناموفق یک بار با استخر دیگر Smartproxy دوباره تلاش شود.

    def process_response(self, request, response, spider):
        retryable = {403, 429}
        already_switched = request.meta.get('smartproxy_pool_retry', False)

        if response.status in retryable and not already_switched:
            current = request.meta.get('proxy_pool', 'residential')
            alternate = 'datacenter' if current == 'residential' else 'residential'

            new_meta = request.meta.copy()
            new_meta['proxy_pool'] = alternate
            new_meta['smartproxy_pool_retry'] = True

            spider.logger.warning(
                'Retrying %s with %s pool after HTTP %s',
                request.url,
                alternate,
                response.status,
            )
            return request.replace(meta=new_meta, dont_filter=True)

        return response

اگر از این پشتیبان استفاده می‌کنید، RETRY_TIMES را پایین نگه دارید تا درخواست‌های مسدودشده بی‌نهایت حلقه نزنند.

مرحله ۸ — spider را اجرا کنید و نتایج را ذخیره کنید

scrapy crawl smartproxy_demo -O smartproxy_results.json

مرحله ۹ — IP خروجی پروکسی را با cURL بررسی کنید

از همان endpoint HTTP Smartproxy خارج از Scrapy استفاده کنید تا اعتبارنامه‌ها و اتصال را تأیید کنید.

curl --proxy 'http://USERNAME:PASSWORD@HOST:PORT' https://httpbin.org/ip

USERNAME، PASSWORD، HOST و PORT را با مقادیر استخری که در حال آزمایش آن هستید جایگزین کنید.

عیب‌یابی

  • 407 Proxy Authentication Required: نام کاربری و رمز عبور را بررسی کنید، مطمئن شوید URL-encoded هستند، و تأیید کنید که از میزبان و پورت درست برای استخر انتخاب‌شده استفاده می‌کنید.
  • Tunnel connection failed یا خطاهای TLS: تأیید کنید که endpoint Smartproxy از هدف‌های HTTPS از طریق HTTP CONNECT پشتیبانی می‌کند. ابتدا آن را با دستور cURL در مرحله ۹ آزمایش کنید.
  • Scrapy پروکسی را نادیده می‌گیرد: تأیید کنید که SmartproxyRotationMiddleware در DOWNLOADER_MIDDLEWARES زیر 750 تنظیم شده است، و اینکه HTTPPROXY_ENABLED برابر True است.
  • 403 یا 429 مکرر: CONCURRENT_REQUESTS_PER_DOMAIN را کاهش دهید، DOWNLOAD_DELAY اضافه کنید، به پروکسی‌های مسکونی سوئیچ کنید، و user agentها را فقط جایی بچرخانید که هدف اجازه می‌دهد.
  • پاسخ‌های کند: پروکسی‌های دیتاسنتری معمولاً برای توان عملیاتی خام بهتر هستند؛ پروکسی‌های مسکونی برای درخواست‌های هدف‌گیری جغرافیایی و سایت‌هایی که محدوده IP دیتاسنتر را مسدود می‌کنند بهترند.
  • اعتبارنامه‌ها شامل @، :، یا / هستند: فراخوانی‌های urllib.parse.quote را در میان‌افزار نگه دارید. Quote کردن از URLهای پروکسی بدشکل جلوگیری می‌کند.

خلاصه

اکنون یک پروژه Scrapy دارید که درخواست‌ها را از طریق پروکسی‌های HTTP مسکونی و دیتاسنتری Smartproxy در لینوکس مسیریابی می‌کند. میان‌افزار برای هر درخواست یک استخر انتخاب می‌کند، اعتبارنامه‌ها را در متغیرهای محیطی نگه می‌دارد، و می‌تواند وقتی هدفی یک IP را مسدود می‌کند به استخر دیگر برگردد. با همزمانی پایین شروع کنید، IPهای خروجی خود را با cURL بررسی کنید، و CONCURRENT_REQUESTS_PER_DOMAIN را فقط پس از اینکه خزش به‌طور قابل‌اعتماد رفتار کرد افزایش دهید.