Skip to content
Advanced / 4 min read

Как использовать резидентные и датацентровые прокси Smartproxy со Scrapy в Linux

Создайте промежуточное ПО загрузчика Scrapy, которое выполняет ротацию резидентных и датацентровых HTTP-прокси Smartproxy в Linux, с учетными данными из переменных окружения и повторными попытками с переключением пулов.

Linux HTTP(S) Веб-скрейпинг

Обзор

Встроенный HttpProxyMiddleware в Scrapy может направлять запрос через один HTTP-прокси, но для производственного скрапинга с Smartproxy обычно нужны две вещи: пул резидентных прокси для геотаргетированных запросов или запросов, устойчивых к блокировкам, и пул датацентровых прокси для высокопроизводительных запросов. В этом руководстве показано, как добавить собственное промежуточное ПО загрузчика, которое выбирает конечную точку Smartproxy для каждого запроса, выполняет ротацию между резидентными и датацентровыми пулами и повторяет типичные ошибки прокси, не прописывая учетные данные жестко в вашем пауке.

Smartproxy поддерживает HTTP и SOCKS5; в этом руководстве используются конечные точки HTTP/HTTPS-прокси, поскольку встроенное промежуточное ПО прокси в Scrapy ожидает URL HTTP-прокси.

Предварительные требования

  • Машина или контейнер Linux с Python 3.10 или новее.
  • Аккаунт Smartproxy с учетными данными резидентных и/или датацентровых прокси.
  • Детали конечных точек из панели управления Smartproxy: хост прокси, порт, имя пользователя и пароль для каждого пула, который вы планируете использовать.
  • Доступные pip и venv.

Шаги

Шаг 1 — Создайте виртуальное окружение и установите Scrapy

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

Шаг 2 — Сохраните учетные данные 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. Храните файл вне системы контроля версий.

Шаг 3 — Создайте проект Scrapy

scrapy startproject smartproxy_scrapy
cd smartproxy_scrapy
scrapy genspider example example.com

Шаг 4 — Добавьте промежуточное ПО для ротации 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

Шаг 5 — Включите промежуточное ПО перед прокси-мидлварью 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 прокси первым.

Шаг 6 — Выбирайте резидентные или датацентровые прокси для каждого запроса

Используйте 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(),
        }

Шаг 7 — Добавьте резервные повторные попытки между пулами

Код 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 низким, чтобы заблокированные запросы не зацикливались бесконечно.

Шаг 8 — Запустите паука и сохраните результаты

scrapy crawl smartproxy_demo -O smartproxy_results.json

Шаг 9 — Проверьте исходящий IP прокси с помощью cURL

Используйте ту же конечную точку Smartproxy HTTP вне Scrapy, чтобы подтвердить учетные данные и подключение.

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

Замените USERNAME, PASSWORD, HOST и PORT на значения для тестируемого пула.

Устранение неполадок

  • 407 Proxy Authentication Required: Проверьте имя пользователя и пароль, убедитесь, что они закодированы для URL, и подтвердите, что вы используете правильный хост и порт для выбранного пула.
  • Tunnel connection failed или ошибки TLS: Убедитесь, что конечная точка Smartproxy поддерживает HTTPS-цели через HTTP CONNECT. Сначала протестируйте ее с помощью команды cURL из шага 9.
  • Scrapy игнорирует прокси: Убедитесь, что SmartproxyRotationMiddleware установлен ниже 750 в DOWNLOADER_MIDDLEWARES, и что HTTPPROXY_ENABLED имеет значение True.
  • Частые 403 или 429: Уменьшите CONCURRENT_REQUESTS_PER_DOMAIN, добавьте DOWNLOAD_DELAY, переключитесь на резидентные прокси и ротируйте user-agent только там, где это разрешено целевым сайтом.
  • Медленные ответы: Датацентровые прокси обычно лучше для чистой пропускной способности; резидентные прокси лучше для геотаргетированных запросов и сайтов, блокирующих диапазоны IP датацентров.
  • Учетные данные содержат @, :, или /: Оставьте вызовы urllib.parse.quote в промежуточном ПО. Квотирование предотвращает некорректные URL прокси.

Итог

Теперь у вас есть проект Scrapy, который направляет запросы через резидентные и датацентровые HTTP-прокси Smartproxy в Linux. Промежуточное ПО выбирает пул для каждого запроса, хранит учетные данные в переменных окружения и может переключаться на другой пул, когда целевой сайт блокирует IP. Начните с низкой конкурентности, проверьте ваши исходящие IP с помощью cURL и увеличивайте CONCURRENT_REQUESTS_PER_DOMAIN только после того, как краулинг будет работать надежно.