scrapy rotating proxies

Scrapy のローテーティングプロキシとは、Scrapy スパイダーが順番に切り替えて使う IP エンドポイントです。連続するリクエストを異なるアドレスから送信することで、レート制限や IP ブロックを受ける可能性を下げられます。このチュートリアルでは、scrapy-rotating-proxies ミドルウェアと DataImpulse のローテーティングレジデンシャルゲートウェイを使って、実際のプロジェクトにローテーティングプロキシを導入し、設定の検証とトラブルシューティングを行う方法を説明します。

ミドルウェアをインストールし、settings.py を設定し、ブロック検出とリトライを設定し、出口 IP が実際に切り替わることを確認したうえで、ローテーティングゲートウェイと固定プロキシリストのどちらを使うべきか判断します。以下のコードブロックはすべてそのまま実行でき、制限事項についても後半で率直に説明します。

DataImpulse は倫理的なプロキシプロバイダーで、195 か国にわたって 9,000 万を超えるレジデンシャル、モバイル、データセンターの IP アドレスを提供します。1 GB あたり 1 ドルからの従量課金モデルを採用し、トラフィックは失効しません。ウェブスクレイピング、広告検証、価格モニタリング、市場調査、複数アカウント管理などに使われています。

重要なポイント

  • セットアップ: Scrapy のローテーティングプロキシは、scrapy-rotating-proxies ミドルウェアをプロキシエンドポイントのリスト、または gw.dataimpulse.com:823 のような単一のローテーティングゲートウェイに向けることで機能し、各リクエストが異なる IP から送信できるようになります。
  • 最適なプロキシの種類: ローテーティングレジデンシャルプロキシ。実際の利用者に割り当てられた IP を利用するため、検出されにくくなります。
  • 料金: 1 GB あたり 1 ドルから、従量課金制で、トラフィックは失効せず、サブスクリプションは不要です。
  • カバレッジ: 195 か国にわたる 9,000 万以上の倫理的に調達された IP。
  • 信頼性: 成功率 99.51%、G2 で 5 段階中 4.8 の評価。
  • プロトコルとターゲティング: HTTP、HTTPS、SOCKS5 に対応し、国別ターゲティングにも対応しています。
Scrapy がリクエストごとにプロキシをローテーションする仕組み

Scrapy でローテーティングプロキシを始める前に必要なものは?

動作する Scrapy プロジェクト、Python 3.8 以降、scrapy-rotating-proxies パッケージ、そしてプロキシエンドポイントのプールへのアクセスが必要です。ローテーション処理はダウンローダーミドルウェアで行われるため、通常はスパイダー側を変更する必要はありません。

コードを書く前に、次のものを用意してください:

  • scrapy startproject で作成した Scrapy プロジェクト。
  • scrapy-rotating-proxies ミドルウェア。これはコミュニティ製パッケージで、使用方法はスクレイピングのワークフローでも解説されており、GitHub で scrapy-rotating-proxies として公開されています。
  • プロキシの認証情報。このガイドでは DataImpulse のレジデンシャルプロキシを使用します。単一のローテーティングゲートウェイに加え、HTTP、HTTPS、SOCKS5 と国別ターゲティングに対応しています。

ミドルウェアをプロジェクトの環境にインストールします:

pip install scrapy-rotating-proxies

このパッケージは 2 つのミドルウェアを追加します。RotatingProxyMiddleware は各リクエストにプロキシを割り当て、BanDetectionMiddleware はレスポンスがブロックを示しているかを判定し、問題のある IP を避けるようローテーションを促します。

Scrapy でローテーティングプロキシをどう使うのか?

settings.py でプロキシエンドポイントを宣言し、2 つのダウンローダーミドルウェアを有効にすることで scrapy-rotating-proxies を追加します。プロキシの指定方法は 2 つあります。settings.py 内の Python リストを使う方法と、ファイルから読み込む方法です。

インライン方式では ROTATING_PROXY_LIST を使います。両方のミドルウェアが正しい順序で実行されるよう、次の優先度で有効にします:

# settings.py
ROTATING_PROXY_LIST = [
    'http://user:[email protected]:823',
]

DOWNLOADER_MIDDLEWARES = {
    'rotating_proxies.middlewares.RotatingProxyMiddleware': 610,
    'rotating_proxies.middlewares.BanDetectionMiddleware': 620,
}

認証情報をソース管理に含めないためには、ROTATING_PROXY_LIST_PATH を使い、1 行に 1 つのプロキシを記載したファイルを指定します:

# settings.py
ROTATING_PROXY_LIST_PATH = 'proxies.txt'
# proxies.txt (one endpoint per line)
http://user:[email protected]:823
http://user:[email protected]:824

DataImpulse のゲートウェイを使えば、長いリストを管理する代わりに単一のエンドポイントを指定できます。gw.dataimpulse.com:823 はプロバイダー側で出口 IP をすでにローテーションしているため、この 1 行だけを指定すれば、ミドルウェアとプロバイダー側の 2 層でローテーションできます。ゲートウェイはリクエストごとに新しいレジデンシャル IP を選び、ミドルウェアはレスポンスがブロックと判定されたときに同じゲートウェイで再試行します。これは大半のクロールで最もシンプルかつ信頼性の高い構成です。

グローバル設定ではなくリクエストごとにプロキシを指定したい場合は、スパイダー内で request の meta に設定します。この方法ではプロキシ認証も明示的に指定でき、DataImpulse のプロキシ認証のガイドで解説されています:

import scrapy

class GatewaySpider(scrapy.Spider):
    name = 'gateway'
    urls = ['https://httpbin.org/ip']

    def start_requests(self):
        proxy = 'http://user:[email protected]:823'
        for url in self.urls:
            yield scrapy.Request(url, meta={'proxy': proxy}, dont_filter=True)

Scrapy でローテーティングプロキシが動作していることをどう検証するのか?

IP を返すエンドポイントに複数のリクエストを送り、レスポンスごとに報告される送信元 IP が変化することを確認すれば、ローテーションを検証できます。httpbin.org/ip は呼び出し元の出口 IP を返すので、簡単な確認に使えます。

エコーエンドポイントに 10 回アクセスし、各出口 IP をログに記録する簡単なスパイダーを追加します:

import scrapy

class IPCheckSpider(scrapy.Spider):
    name = 'ipcheck'
    start_urls = ['https://httpbin.org/ip'] * 10

    def parse(self, response):
        self.logger.info('Exit IP: %s', response.json()['origin'])

プロジェクトのルートから実行します:

scrapy crawl ipcheck

ログには Exit IP の異なる値が複数表示されるはずです。すべての行が同じアドレスを示す場合、ローテーションは有効になっていません。ミドルウェアが有効になっていること、ROTATING_PROXY_LIST が空でないこと、リクエストが HTTP キャッシュから返されていないことを確認してください。ミドルウェアはプロキシの状態もログに記録します。プールの状態を把握するため、good、dead、reanimated のプロキシに関する行を確認してください。

Scrapy のローテーティングプロキシでブロックや 407 エラーをどうトラブルシューティングするのか?

ローテーションに関する問題の大半は、次の 2 点に集約されます。ミドルウェアがブロックを正しく検出しているか、そしてプロキシ認証が設定されているか、です。ブロック検出が弱いと、ブロック検出が不十分だと、ブロックされた IP が有効でないレスポンスを返し続けます。認証設定が誤っている場合は HTTP 407 が返されます。

推測に頼らずブロックを検出するために、このガイドでは Scrapy 向けの 4 シグナルブロック検出モデルを提案します。各レスポンスを 4 つの独立したシグナルで評価し、1 回の誤検出だけで正常なプロキシを除外しないようにします:

  • ステータスコード: 403、429、503 はブロック候補として扱い、200、301、302 は健全として扱います。
  • リダイレクト先: ログイン、captcha、またはチャレンジのパスへの 302 リダイレクトは、ステータスが正常に見えても緩やかなブロックの兆候です。
  • 本文のフィンガープリント: captcha、アクセス拒否、または本物のページなら決して返さない空のペイロードといったマーカーがないか本文をスキャンします。
  • レイテンシ: 移動平均よりはるかに遅いレスポンスは、完全なブロックの前にスロットリングを示していることがよくあります。

このポリシーをクラスとして実装し、BanDetectionMiddleware がデフォルトではなく独自のロジックを使うよう登録します:

# ban_policy.py
class DataImpulseBanPolicy:
    NOT_BAN_STATUSES = {200, 301, 302}

    def response_is_ban(self, request, response):
        if response.status in (403, 429, 503):
            return True
        if b'captcha' in response.body.lower():
            return True
        if not response.body:
            return True
        return False

    def exception_is_ban(self, request, exception):
        return True
# settings.py
ROTATING_PROXY_BAN_POLICY = 'myproject.ban_policy.DataImpulseBanPolicy'

検出機構をリトライとバックオフに組み合わせ、フラグが立ったリクエストが失敗する前に新しい IP へ切り替わるようにします。Scrapy はリトライコードを処理し、ミドルウェアはページ単位のプロキシリトライを処理します:

# settings.py
RETRY_ENABLED = True
RETRY_TIMES = 5
RETRY_HTTP_CODES = [403, 407, 429, 500, 502, 503, 504]
ROTATING_PROXY_PAGE_RETRY_TIMES = 5

プロキシプールを使い切らないよう、スロットリングを追加します。DOWNLOAD_DELAY はリクエストの間隔を空け、AUTOTHROTTLE はサーバーのレイテンシに応じて遅延を調整します:

# settings.py
DOWNLOAD_DELAY = 1.0
CONCURRENT_REQUESTS = 16
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 1.0
AUTOTHROTTLE_MAX_DELAY = 10.0
AUTOTHROTTLE_TARGET_CONCURRENCY = 4.0

リクエストが HTTP 407 を返す場合、ターゲットサイトがブロックしているのではなく、プロキシが認証情報を拒否しています。発行されたユーザー名とパスワードが正確にプロキシ URL に埋め込まれており、特殊文字を含む場合は URL エンコードされていることを確認してください。詳しい診断は DataImpulse のHTTP 407 エラーのガイドにあります。JavaScript の実行後にしかコンテンツを表示しないサイトには、ヘッドレス層も必要で、これは動的なウェブページをスクレイピングする方法で解説されています。

どのローテーティングプロキシ構成があなたの Scrapy プロジェクトに合うのか?

大半のクロールにはローテーティングゲートウェイを、個々の IP を制御する必要がある場合は固定プロキシリストを、特殊なローテーションルールが必要な場合にのみカスタムミドルウェアを使います。選択の基準は、必要な制御の度合いと運用負荷のバランスです。

次の判断基準を参考にしてください:

  • 次の場合はローテーティングゲートウェイを使う場合: 1 つのエンドポイントでリクエストごとに IP を変えたいとき、ターゲットが IP 単位でレート制限を課すとき、そしてプロキシファイルをまったく管理したくないとき。
  • 次の場合は静的なプロキシリストを使う場合: 再現可能なセッションが必要なとき、スパイダーごとに特定のリージョンを固定したいとき、または使用したエンドポイントを正確に監査しなければならないとき。
  • 次の場合はカスタムミドルウェアを避ける場合: scrapy-rotating-proxies がすでにニーズを満たしているとき。独自のミドルウェアはメンテナンスと、それ自体のブロック検出のバグを増やすためです。
  • 次の場合はローテーティングゲートウェイを避ける場合: 複数ステップのログインをまたいで同じ IP を保持する必要があるワークフローのとき。そこではスティッキーセッションが代わりに適切なツールです。

3 つのアプローチの比較は次のとおりです:

アプローチ ローテーションの制御 設定の手間 最適な用途
ローテーティングゲートウェイ(単一エンドポイント) プロバイダーがリクエストごとにローテーション 最小、settings に 1 行 大規模なクロール、IP 単位のレート制限への対応
プロキシリストファイル ミドルウェアがエンドポイントを巡回 中程度、プロキシファイルを維持 リージョン固定、監査可能なプール
カスタムミドルウェア 完全に制御可能、自らロジックを実装 最大、コードとテスト 非標準のローテーションルール

DataImpulse はゲートウェイからローテーションを提供し、継続性が必要なときはスティッキーセッションもサポートします。そのため多くのチームはゲートウェイから始め、リージョンを固定しなければならない少数のスパイダーのためにリストファイルを取っておきます。レジデンシャルの信頼性よりもコストと速度が重要なら、データセンターのプロキシモバイルのプロキシが同じアカウントで使える代替手段です。

Scrapy におけるローテーティングプロキシの制限とリスクは何か?

ローテーティングプロキシは IP ベースのブロックを減らしますが、スクレイパーを検出不能にするものではなく、不適切な挙動のスパイダーを改善するものでもありません。ローテーションは 1 つの層であり、保証ではありません。

次の制限を念頭に置いてください:

  • ローテーションだけではフィンガープリンティングを回避できない。 サイトはヘッダー、TLS シグネチャ、挙動もプロファイリングするため、デフォルトの Scrapy user agent を使った新しい IP でもフラグが立つことがあります。
  • captcha は依然として発生する。 ローテーティング IP は発生頻度を下げられますが、完全には解決できません。captcha 対策か、より遅いクロールが依然として必要です。
  • 地域設定の不一致は問題を招く。 ある国をターゲットにしながら別のリージョンを想定したローカライズページを要求すると、ローテーションが機能していてもレスポンスの内容が想定と異なることがあります。
  • 過度な並行処理は逆効果になる。 並行リクエストが多すぎるとプロキシプールを消耗させ、ブロック率を高めます。だからこそ AUTOTHROTTLE が重要です。
  • 法律と利用規約の制限が適用される。 ローテーションは信頼性のためのツールであって、許可ではありません。robots ディレクティブ、レート制限、適用される法律を尊重してください。

範囲について、DataImpulse が何であるかを明確にしておきます。195 か国にわたる 9,000 万以上の IP を持つ、倫理的でオプトインのプロキシネットワークで、1 GB あたり 1 ドルからの従量課金、成功率は 99.51 パーセントです。解析済みデータを返すマネージドスクレイピング API ではなく、静的な ISP プロキシや無料のウェブプロキシを提供するサービスでもありません。クロールを行うのは依然として Scrapy であり、プロキシはリクエストの出口を変えるだけです。

ローテーティングミドルウェアにおける 4 シグナルのブロック検出

よくある質問

Scrapy でローテーティングプロキシをどう使うのか?

scrapy-rotating-proxies をインストールし、settings.py の ROTATING_PROXY_LIST または ROTATING_PROXY_LIST_PATH にエンドポイントを追加し、RotatingProxyMiddleware と BanDetectionMiddleware のダウンローダーミドルウェアを有効にします。これにより各リクエストは異なる IP から送信されます。

ローテーティングゲートウェイとプロキシリストの違いは何か?

ローテーティングゲートウェイは、プロバイダー側でリクエストごとに出口 IP を変える単一のエンドポイントなので、1 行を設定します。プロキシリストはミドルウェアが巡回する多数のエンドポイントを指定する方式で、リージョンを固定したり特定の IP を監査したりする必要があるときに適しています。

Scrapy のローテーティングプロキシでなぜ HTTP 407 エラーが出るのか?

HTTP 407 は、ターゲットサイトがブロックしたのではなく、プロキシが認証を拒否したことを意味します。ユーザー名とパスワードがプロキシ URL に埋め込まれ、特殊文字を含む場合は URL エンコードされていることを確認してください。

Scrapy のプロキシが実際にローテーションしていることをどう確認できるのか?

httpbin.org/ip のような IP を返すエンドポイントに複数のリクエストを送り、origin フィールドをログに記録します。報告される IP がレスポンスごとに変わればローテーションは有効です。同じままなら、ミドルウェアが有効になっていること、HTTP キャッシュがオフになっていることを確認してください。

ローテーティングプロキシはすべてのスクレイピングブロックを止めるのか?

いいえ。ローテーションは IP ベースのレート制限とブロックを減らしますが、サイトはフィンガープリンティング、captcha、挙動チェックも使います。信頼できるクロールのために、ローテーションを適切な遅延、実際のブラウザに近いヘッダー、AUTOTHROTTLE と組み合わせてください。

DataImpulse が適さないのはどんなときか?

静的な ISP プロキシ、完全にマネージドなスクレイピング API、または銀行や政府のサイトへのアクセスが必要な場合、DataImpulse は適切なツールではありません。公開データの収集とコンテンツへのアクセスのための、ローテーティングのレジデンシャル、モバイル、データセンターのプロキシに特化しています。

Scrapy でプロキシのローテーションを始めよう

scrapy-rotating-proxies を DataImpulse のローテーティングゲートウェイに向け、各リクエストが新しいレジデンシャル IP から送信されるようにします。1 GB あたり 1 ドルから従量課金アカウントを作成して、ゲートウェイの設定をそのまま settings.py に追加できます。


Share article: