# レジデンシャルプロキシ用 Scrapy ミドルウェアの概要

> Scrapy の回転プロキシミドルウェア：リクエストごとにレジデンシャルIPを回転・固定、AutoThrottle とリトライ設定、scrapy-playwright対応。文法チェック済みコード。

- URL: https://crawlrelay.com/ja/docs/scrapy/
- 最終更新: 2026-10-13
- Publisher: CrawlRelay (https://crawlrelay.com)

リクエストごとに国とセッションを選ぶ30行のダウンローダーミドルウェアのコードと、クロールのマナーを保つ設定：robots.txt、ドメインごとの同時接続数制限、AutoThrottle、リトライ。

**クイックアンサー — Scrapy で回転プロキシを使うには？**

Scrapy の `HttpProxyMiddleware` の前に動く小さなダウンローダーミドルウェアで `request.meta["proxy"]` を `http://USERNAME:PASSWORD@gw.crawlrelay.com:7777` にセットすると、Scrapy が認証情報を送ります。**CrawlRelay** のレジデンシャルプロキシならユーザ名に国と固定セッションを入れるので、一つのミドルウェアで両方対応可能。トラフィックは50 GBから$0.50/GBで課金。仮想通貨決済、KYC不要。

## Scrapy セットアップの概要

| 属性 | 値 |
| --- | --- |
| プロキシをセットする場所 | `request.meta["proxy"]`、ミドルウェアで設定 |
| ミドルウェアの順序 | 組み込みの `HttpProxyMiddleware` 優先度750以下にあなたのミドルウェアを配置 |
| 認証情報 | プロキシ URL 内；Scrapy が `Proxy-Authorization` ヘッダーに変換 |
| SOCKS5 | デフォルトのHTTP/1.1ハンドラーでは使えません；Scrapy 2.17以降は HttpxDownloadHandler 経由で SOCKS が利用可能。HTTPポート 7777 が最もシンプル |
| ローテーション | 新規接続ごとに新しい出口IP；リクエストごとにユニークなセッションIDが違うIPを生む通常の動作 |
| マナーの設定 | `ROBOTSTXT_OBEY`、`CONCURRENT_REQUESTS_PER_DOMAIN`、`AUTOTHROTTLE_ENABLED` |
| リトライ | 429 や 5xx はデフォルトの `RETRY_HTTP_CODES` に含まれ、Retry-After は読み取りません |

## プロキシミドルウェアはどう書く？

クラスは `middlewares.py` に入れます。ユーザー名は設定と3つのオプション `meta` キー：`proxy_country`、`proxy_session`、`proxy_ttl` から生成されます。`proxy_session` がないリクエストは回転し、`proxy_session="new"` があるリクエストは新セッションなので通常は異なる出口IPが得られます。固定セッションID付きリクエストは同じフロー内のリクエストと出口を共有。ミドルウェアは各パス（リトライ含む）でプロキシを再計算し、他のコードで設定済みのプロキシはそのままにします。`CRAWLRELAY_USER` がないとクロールは自身のIPで起動時に停止します。

*middlewares.py*

```python
import uuid
from urllib.parse import quote


class CrawlRelayProxyMiddleware:
    """Sets request.meta["proxy"]; Scrapy's HttpProxyMiddleware then sends the credentials."""

    def __init__(self, user, password, country):
        self.user, self.password, self.country = user, password, country

    @classmethod
    def from_crawler(cls, crawler):
        s = crawler.settings
        if not s.get("CRAWLRELAY_USER"):
            # Fail loudly: NotConfigured would only disable the middleware and crawl from your own IP
            raise ValueError("CRAWLRELAY_USER is not set: refusing to crawl without the proxy")
        return cls(s.get("CRAWLRELAY_USER"), s.get("CRAWLRELAY_PASSWORD", ""), s.get("CRAWLRELAY_COUNTRY", "us"))

    def process_request(self, request, spider=None):
        if "proxy" in request.meta and not request.meta.get("_crawlrelay"):
            return None  # a proxy set by other code: leave it alone
        parts = [self.user, "country", request.meta.get("proxy_country", self.country)]
        session = request.meta.get("proxy_session")
        if session == "new":  # a fresh session for this request (and for each of its retries)
            session = uuid.uuid4().hex[:12]
        if session:
            parts += ["session", session, "ttl", str(request.meta.get("proxy_ttl", 10))]
        username = "-".join(parts)
        request.meta["proxy"] = "http://%s:%s@gw.crawlrelay.com:7777" % (
            quote(username, safe=""), quote(self.password, safe=""))
        request.meta["_crawlrelay"] = True
        return None
```

## どの Scrapy 設定がプロキシ利用時のクロールをマナー良く高速に保つ？

プロキシはリクエストを多くのIPに分散しますが、対象サーバーには合計リクエスト率が見えてしまいます。これらの設定はドメインごとの適正なペースを保ち、AutoThrottle が応答速度に応じて自動調整します。`ROBOTSTXT_OBEY = True` は新規 Scrapy プロジェクトで既に設定済みです。

*settings.py（一部抜粋）*

```python
import os

BOT_NAME = "myproject"
ROBOTSTXT_OBEY = True
USER_AGENT = "ExampleCrawler/1.0 (+https://example.com/crawler-info)"

CRAWLRELAY_USER = os.environ.get("CRAWLRELAY_USER")  # e.g. the username from your dashboard
CRAWLRELAY_PASSWORD = os.environ.get("CRAWLRELAY_PASSWORD")
CRAWLRELAY_COUNTRY = "us"

DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.CrawlRelayProxyMiddleware": 350,  # runs before HttpProxyMiddleware (750)
}

CONCURRENT_REQUESTS = 32
CONCURRENT_REQUESTS_PER_DOMAIN = 4
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 1.0
AUTOTHROTTLE_MAX_DELAY = 30.0
AUTOTHROTTLE_TARGET_CONCURRENCY = 2.0

RETRY_ENABLED = True
RETRY_TIMES = 3
RETRY_HTTP_CODES = [429, 500, 502, 503, 504, 522, 524, 408]
DOWNLOAD_TIMEOUT = 45
```

## ページネーションでは1つのIPを保持し、アイテムページではIPを回転させるにはどうすればいいですか？

前のページに依存するフローのリクエストには固定された`proxy_session`を渡し、独立したページには渡さないでください。以下のスパイダーは、スクレイピング練習用に公開されたsandboxサイト books.toscrape.comで動作します。

*spiders/catalog.py*

```python
import scrapy


class CatalogSpider(scrapy.Spider):
    name = "catalog"
    start_urls = ["https://books.toscrape.com/"]

    def parse(self, response):
        for href in response.css("article.product_pod h3 a::attr(href)").getall():
            # Product pages are independent: rotating exits
            yield response.follow(href, callback=self.parse_item)
        next_page = response.css("li.next a::attr(href)").get()
        if next_page:
            # The listing flow keeps one sticky exit for 30 minutes
            yield response.follow(next_page, callback=self.parse,
                                  meta={"proxy_session": "listing1", "proxy_ttl": 30})

    def parse_item(self, response):
        yield {
            "title": response.css("div.product_main h1::text").get(),
            "price": response.css("p.price_color::text").get(),
            "url": response.url,
        }
```

## Scrapyは接続を再利用しますか？それは回転を妨げますか？

はい、Scrapyはプロキシとターゲットホストごとに接続を維持し再利用します。そのため連続リクエストは同じ出口を共有します。ほとんどのクロールでは問題ありません。Scrapyはサイトごとに最大`CONCURRENT_REQUESTS_PER_DOMAIN`の接続を開き、新しい接続は通常異なるレジデンシャルプロキシIPを取得します。

新しいIP経由でリクエストを出す必要がある場合（例えば失敗した出口からの502](https://crawlrelay.com/ja/docs/errors/502-bad-gateway/)時のリトライ）は、`response.request.replace(meta={**response.meta, "proxy_session": "new"}, dont_filter=True)`を使って再発行してください。ミドルウェアは新しいセッションユーザー名を作成し、異なるユーザー名は異なる接続プールを意味するため、Scrapyは新しい接続を開き、ゲートウェイは通常異なる出口を割り当てます。

## Scrapyで429レスポンスのRetry-Afterを尊重するには？

Scrapyの組み込み`RetryMiddleware`は429をリトライしますが、`Retry-After`ヘッダーの待機はしません。AutoThrottleはドメインの速度を徐々に落とすので通常問題ありません。長い`Retry-After`値を送るAPIの場合、小さなミドルウェアを追加しヘッダーを読み取り遅延付きでリトライをスケジュールするか、そのドメインの`CONCURRENT_REQUESTS_PER_DOMAIN`を下げましょう。[429ページ](https://crawlrelay.com/ja/docs/errors/429-too-many-requests/)でヘッダーの意味を説明しています。

## scrapy-playwrightでプロキシを使うには？

JavaScriptが必要なページでは、scrapy-playwrightはPlaywrightの起動オプションを設定経由で渡します。認証情報は別々に指定してください：ChromiumはサーバーURL内の認証情報を無視します。ログアウト状態の複数ページにわたるフローをレンダリングする場合は、セッションごとに1つのコンテキストを使います。

*scrapy-playwright用settings.py*

```python
import os

DOWNLOAD_HANDLERS = {
    "http": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
    "https": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
}
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"

PLAYWRIGHT_LAUNCH_OPTIONS = {
    "proxy": {
        "server": "http://gw.crawlrelay.com:7777",
        "username": os.environ.get("CRAWLRELAY_USER", "USERNAME") + "-country-us",
        "password": os.environ.get("CRAWLRELAY_PASSWORD", "PASSWORD"),
    },
}
```

## Scrapyとプロキシ：よくある質問

### scrapy-rotating-proxiesやプロキシリストは必要ですか？

いいえ。これらのパッケージは個別のプロキシアドレスのリストをローテーションし、失敗したものを禁止します。レジデンシャルゲートウェイでは、ローテーションは1つのアドレスの背後で行われ、新しい接続ごとに通常異なるレジデンシャルプロキシIPが割り当てられます。`request.meta["proxy"]`を設定する単一のミドルウェアだけで十分です。

### なぜScrapyでプロキシにTunnelErrorが出ますか？

`TunnelError: Could not open CONNECT tunnel`はプロキシがHTTPSサイトへのCONNECTリクエストを拒否または失敗したことを意味します。メッセージのステータスコードで理由がわかります：407は認証情報、502や504は出口またはターゲットの問題です。[407](https://crawlrelay.com/ja/docs/errors/407-proxy-authentication-required/)、[502](https://crawlrelay.com/ja/docs/errors/502-bad-gateway/)のページを参照してください。

### ドメインあたり同時リクエスト数はどれくらいが適切ですか？

ドメインごとに2〜4から始め、AutoThrottleに任せて調整します。429、403、5xxの割合が安定している間だけ増やし、サイトの応答時間を監視してください。大規模サイトはより多く許容可能で、小規模サイトはリクエスト間遅延や単一接続が必要かもしれません。

### もっとデータを取得するためにROBOTSTXT_OBEYを無効にすべきですか？

いいえ。robots.txtはサイトが自動クライアントに許可するパスを示すもので、RFC 9309で2022年に標準化されました。これを無視すると法的・倫理的リスクが上がり、サイトが除外したコンテンツを取得するために当社の[Acceptable Use Policy](https://crawlrelay.com/ja/acceptable-use/)に違反する恐れがあります。

### Scrapyクロールはどれくらいのトラフィックを使いますか？

ScrapyはHTMLのみをダウンロードするため、ページごとに数十キロバイト程度（圧縮済み）です。実行終了時にScrapyが表示するstats内の`downloader/response_bytes`値をレスポンス数で割って確認してください。[帯域幅ガイド](https://crawlrelay.com/ja/guides/bandwidth-calculator/)でコスト換算できます。

**レジデンシャルIPをScrapyプロジェクトに組み込む** $5.94を10 GBでテスト、$0.50/GBは50 GBから。 [料金を見る](https://crawlrelay.com/ja/pricing/) · [同時実行性ガイド](https://crawlrelay.com/ja/docs/concurrency/)

---

CrawlRelay: CrawlRelayは開発者第一のレジデンシャルプロキシおよび4G/5Gモバイルプロキシの回転型サービスです：有効期限なしの使った分だけ支払うトラフィックを$0.50/GBから暗号通貨で購入、IDアップロード不要。KYC不要 — IDもセルフィーも書類も不要。暗号通貨で支払い可能。
