> ## Documentation Index
> Fetch the complete documentation index at: https://docs.catproxy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Python: Scrapy

> Интегрируйте прокси Catproxy в свои проекты Scrapy для надёжного парсинга в больших масштабах. Изучите передовые практики на реальном примере.

[Scrapy](https://scrapy.org/) - мощный фреймворк для масштабного парсинга. Лучший способ управления прокси в Scrapy - использовать кастомный **Downloader Middleware**. Это позволяет централизовать логику прокси и держать пауков чистыми.

### Шаг 1: Создайте Proxy Middleware

Сначала создадим middleware, который будет прикреплять учётные данные прокси к каждому запросу.

1. В вашем проекте Scrapy откройте файл `middlewares.py`.
2. Добавьте следующий класс. Он считывает учётные данные из `settings.py` и легко расширяется для работы с динамическими параметрами.

```python middlewares.py icon="python" lines wrap theme={null}
# my_project/middlewares.py
import base64

class ScrapyCatproxyProxyMiddleware:
    def process_request(self, request, spider):
        # По умолчанию — статические настройки прокси
        proxy_user = spider.settings.get('PROXY_USER')
        proxy_pass = spider.settings.get('PROXY_PASS')

        # Позволяет spider’ам переопределять прокси для каждого запроса
        if 'proxy_username_params' in request.meta:
            params = request.meta['proxy_username_params']
            proxy_user = f"{spider.settings.get('PROXY_USER')}{params}"

        # Задайте прокси для запроса
        request.meta['proxy'] = f"http://{spider.settings.get('PROXY_HOST')}:{spider.settings.get('PROXY_PORT')}"

        # Добавьте заголовок Proxy-Authorization для авторизации
        proxy_auth = f"{proxy_user}:{proxy_pass}"
        auth_header = 'Basic ' + base64.b64encode(proxy_auth.encode()).decode()
        request.headers['Proxy-Authorization'] = auth_header

        spider.logger.info(f"Using proxy user: {proxy_user} for {request.url}")
```

<Info>
  Это продвинутое middleware позволяет передавать динамические параметры (например, `-country-de`) из паука в middleware с помощью `request.meta['proxy_username_params']`.
</Info>

### Шаг 2: Настройте `settings.py`

Теперь включим middleware и добавим ваши учётные данные.

1. Откройте файл `settings.py`.
2. Добавьте базовые учётные данные прокси.
3. Включите `ScrapyCatproxyProxyMiddleware` в `DOWNLOADER_MIDDLEWARES`.

```python settings.py icon="python" lines wrap theme={null}
# my_project/settings.py

# --- Catproxy Proxy Credentials ---
PROXY_HOST = "proxy.catproxy.net"
PROXY_PORT = 5555
PROXY_USER = "PROXY_USERNAME" # Without any parameters
PROXY_PASS = "PROXY_PASSWORD"

# --- Enable the Middleware ---
# The number (e.g., 610) should be high enough to run after default middlewares,
# but before any middlewares that might depend on the proxy.
DOWNLOADER_MIDDLEWARES = {
   'my_project.middlewares.ScrapyCatproxyProxyMiddleware': 610,
}
```

**Ваша базовая настройка завершена!** Любой запрос от любого паука в вашем проекте теперь будет автоматически использовать прокси Catproxy.

### Практический пример: Парсинг спецпредложений Steam

Теперь используем созданное middleware для парсинга всех игр со скидками из магазина Steam. Этот паук стал намного чище, поскольку вся логика прокси находится в middleware.

### Паук (`steam_specials_spider.py`)

Обратите внимание, насколько чист этот паук. Он сосредоточен исключительно на логике парсинга и передаче динамических параметров в middleware.

```python spiders/steam_specials_spider.py icon="python" lines wrap theme={null}
import scrapy
import random

class SteamSpecialsSpider(scrapy.Spider):
    name = "steam_specials"
    start_urls = ["https://store.steampowered.com/specials"]

    def start_requests(self):
        # Create a unique session ID for this job
        session_id = f"steam-special-{random.randint(1000, 9999)}"

        # Define the parameters we want to pass to our middleware
        # We will use the same sticky session for all pages
        proxy_params = f"-country-us-session-{session_id}"

        cookies = {'birthtime': '568022401', 'wants_mature_content': '1', 'steamCountry': 'US|...'}

        for url in self.start_urls:
            yield scrapy.Request(
                url,
                callback=self.parse,
                # Pass our dynamic parameters to the middleware
                meta={'proxy_username_params': proxy_params},
                cookies=cookies,
                headers={
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36'
                }
            )

    def parse(self, response):
        # Extract data from the current page
        games = response.css('a.salepreviewwidgets_SaleItemBrowserRow_y9MSd')

        if not games:
            self.logger.warning("No games found on page. The CSS selector might be outdated.")
            return

        for game in games:
            yield {
                'title': game.css('div.salepreviewwidgets_StoreSaleWidgetTitle_3jI46::text').get(),
                'original_price': game.css('div.salepreviewwidgets_StoreOriginalPrice_2e_2G::text').get(),
                'discount_price': game.css('div.salepreviewwidgets_StoreSalePriceBox_Wh0L8::text').get(),
            }

        # Find and follow the "Next" page link
        next_page_link = response.css('a.paging_Arrow_2JZe3[href*="specials?page="]:last-of-type').get()
        if next_page_link:
            # Scrapy automatically carries over the `meta` dictionary,
            # so our middleware will continue to use the same session!
            yield response.follow(next_page_link, callback=self.parse)
        else:
            self.logger.info("Last page reached. Finishing crawl.")

```

<Warning>
  **CSS-селекторы могут меняться!** Такие сайты, как Steam, часто обновляют дизайн. CSS-селекторы в этом примере актуальны на момент написания, но в будущем может потребоваться их обновление.
</Warning>

### Что демонстрирует этот пример

* **Лучшая практика:** Паук чист и сфокусирован на том, **что** парсить. Middleware обрабатывает, **как** подключиться. Это надёжный и масштабируемый подход.
* **Динамическое управление:** Паук может легко изменить геолокацию или сессию для любого запроса, просто изменив значение `proxy_username_params` в словаре `meta`.
* **Переиспользование кода:** `ScrapyCatproxyProxyMiddleware` теперь может использоваться **всеми пауками** в вашем проекте без дублирования кода.
