Geonode logo
Carl Gamutan

Carl Gamutan

更新日:2026年10月7日

公開日:2026年10月2日

Scrapyでプロキシを使用する方法

Scrapyは、大規模なデータクローリングやデータ抽出を行うためのPythonフレームワークです。ここでは、プロキシを接続する方法、ローテーションやスティッキーセッションの設定方法、および発生するエラーの解決方法について説明します。

Scrapyにプロキシが必要な理由

Scrapy用のプロキシを使用すると、ツールは実行中のマシンのIPアドレスを常に使用するのではなく、別のIPアドレス経由で接続できるようになります。これは、位置情報に基づくタスクや、テスト、監視、その他接続元が重要な作業において役立ちます。

Scrapyは依然としてメインのタスクを処理します。プロキシは、接続がどこから来ているかを処理します。

プロキシがないとどうなるか:IPブロック、レート制限、地域制限

プロキシがないと、ウェブサイトには常に同じIPアドレスが認識されます。アクセスが増えると、そのIPアドレスがレート制限にかかったり、ブロックされたりする可能性があります。

所在地も重要な要素となります。ドイツからアクセスしたページと、米国からアクセスしたページでは、表示されるコンテンツが異なる場合があります。

Scrapy用のプロキシを使用すれば、必要に応じて異なるIPアドレスや所在地から接続することが可能になります。

Scrapy で使用するプロキシの種類

適切なプロキシの種類は、ジョブによって異なります。

プロキシの種類スクレイピングアカウント管理テストモニタリング
レジデンシャル所在地やIPのソースが重要な場合に適しているアカウントにレジデンシャルIPが必要な場合に有用所在地に基づくテストに適している異なる場所からのコンテンツ確認に有用
ISP安定したIPが必要な場合に適している1つのIPで長時間のセッションを行う際に有用一貫したIPでのテストに適している同じIPからの継続的なチェックに有用
データセンター速度と大量のリクエストに適しているレジデンシャルIPが不要な場合に適している一般的なテストに適している頻繁な自動チェックに適している

住宅用プロキシは、IPの送信元や場所が重要な場合に役立ちます。ISPプロキシは、同じIPを長期間アクティブに保つ必要がある場合に適しています。データセンタープロキシは、速度とスケールが主な焦点となる場合に適しています。

最適な選択肢は、そのタスクにジオターゲティング、安定した接続、あるいはより大規模なIPプールへのアクセスが必要かどうかも左右します。

Scrapyでプロキシを接続する方法

Scrapyのプロキシ設定には、Geonodeのホスト、ポート、ユーザー名、パスワードが必要です。これらの認証情報を環境変数に設定しておき、コード内でプロキシを設定する際に読み込みます。

Geonode をご利用ですか?ユーザー名とパスワードは アクセス認証情報 から、ホスト、ポート、プロトコルは プロキシサーバー情報 から取得してください。

設定パスまたはコード

テストのために、ダウンロード用ミドルウェアを追加しました:

DOWNLOADER_MIDDLEWARES = {
    "geonode_scrapy.middlewares.GeonodeProxyMiddleware": 350,
    "scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": 400,
}

このミドルウェアは、request.meta["proxy"]

を通じてプロキシ URL を渡し、Scrapy の HttpProxyMiddleware

がそれを利用します:

request.meta["proxy"] = proxy_url

また、個々のリクエストに対して直接プロキシを渡すこともできます:

yield scrapy.Request(
    url,
    meta={"proxy": proxy_url},
)

実際のユーザー名とパスワードは、Python ファイルに直接記述するのではなく、環境変数に保存してください。この設定により、テストではプロキシ経由で HTTP 200 が正常に返されました。

認証形式「host:port:user:pass」(例:

Geonode

)では、4つの値が返されます:

proxy.geonode.io:PORT:USERNAME:PASSWORD

Scrapyでは、プロキシURLと同じ詳細情報が必要です:

http://USERNAME:PASSWORD@proxy.geonode.io:PORT

認証情報または完全なプロキシ値を環境変数に保存します:

GEONODE_PROXY_URL=http://USERNAME:PASSWORD@proxy.geonode.io:PORT

その後、Pythonで読み込みます:

import os

proxy_url = os.environ["GEONODE_PROXY_URL"]

今回のHTTPテストでは、結果として以下の形式になりました:

http://USERNAME:PASSWORD@proxy.geonode.io:9000

認証を確認するため、誤った認証情報を使用してリクエストを実行しました。 ScrapyはHTTP 407エラーを受け取り、以下のレスポンスが返されました:

Authentication error. Please check your authentication settings.

ScrapyはHttpErrorMiddleware

を通じて、レスポンスをHttpError('Ignoring non-200 response')

として表示しました。

ScrapyにおけるIPローテーションとスティッキーセッション

リクエストで同じIPを維持する必要がない場合は、IPローテーションを使用してください。

今回のテストでは、IPローテーションを行うGeonode

プロキシをScrapyに渡しました:

proxy_url = "http://USERNAME:PASSWORD@proxy.geonode.io:9000"

yield scrapy.Request(
    url,
    meta={"proxy": proxy_url},
)

5つのリクエストを連続して実行しました:

Request 1: 101.98.231.191
Request 2: 101.98.231.191
Request 3: 101.98.231.191
Request 4: 122.164.83.189
Request 5: 122.164.83.189

Unique IPs: 2
Rotation: Yes

テストの結果、IPローテーションは行われたものの、リクエストごとにIPが変更されるわけではなかったことが確認されました。

関連するリクエストを同じIPで処理する必要がある場合は、代わりにスティッキーセッションを使用してください:

proxy_url = (
    "http://USERNAME-session-blogtest01-lifetime-10:"
    "PASSWORD@proxy.geonode.io:10000"
)

同じセッションを使用して3つのリクエストを実行しました:

Request 1: 177.73.202.78
Request 2: 177.73.202.78
Request 3: 177.73.202.78

Same IP: Yes

このテストでは、3つのリクエストすべてで同じIPが使用されました。

利用可能な設定については、Geonode

のガイドにあるローテーションプロキシおよびスティッキーセッションを参照してください。

Scrapyでよく発生するプロキシエラーとその解決方法

プロキシが機能していない場合は、まず接続情報を確認してください。ユーザー名とパスワードを確認した後、ホスト、ポート、プロトコルを確認します。Scrapyから返されるエラーメッセージは、通常、問題の原因を絞り込むのに役立ちます。

407 プロキシ認証が必要

407 エラーは通常、認証に関する問題を示しています。

誤った認証情報でScrapyをテストしたところ、プロキシから次のような応答が返されました:

HTTP status: 407
Authentication error. Please check your authentication settings.

まず、ユーザー名とパスワードを確認してください。それらが正しい場合は、Scrapyがスキーム、認証情報、ホスト、ポートを含む完全なプロキシURLを受け取っていることを確認してください。

ERR_TUNNEL_CONNECTION_FAILED / 接続が拒否されました

接続エラーは通常、Scrapyがプロキシに接続できなかったことを意味します。

まず、ホスト名とポート番号を確認してください。次に、プロトコルが使用中のプロキシサーバーと一致していることを確認してください。

Scrapyは必ずしもブラウザ形式のERR_TUNNEL_CONNECTION_FAILEDを返すとは限りません。接続失敗のテストでは、Scrapyはリクエストを再試行し、最終的にはTwistedのConnectionLostエラーを含むDownloadFailedErrorを返しました。

タイムアウトと空のレスポンス

タイムアウトとは、設定された時間内にリクエストに対してレスポンスが返されなかったことを意味します。

まず、対象のURLが正常に動作しているか、プロキシに接続できるかを確認してください。両方が正常に動作している場合は、Scrapyのタイムアウト設定を確認してください。

接続失敗のテストでは、DOWNLOAD_TIMEOUT=5

という無効なプロキシポートを使用しました。再試行の後、Scrapy は次のように返しました:

DownloadFailedError(
  ConnectionLost:
  Connection to the other side was lost in a non-clean fashion.
)

したがって、プロキシ接続の失敗は、単なるタイムアウトメッセージではなく、接続エラーとして表示される場合があります。

Scrapy特有のエラー

Scrapy特有のよくあるミスとして、request.meta["proxy"]

に不完全な値を渡してしまうことが挙げられます。

今回のテストでは、

proxy.geonode.io:9000

というように、スキームや認証情報を指定せずにリクエストを送信しました。その結果、HTTP 407 が返されました。

この問題を解決するには、完全なプロキシURL(

http://USERNAME:PASSWORD@proxy.geonode.io:9000

)を渡すか、ダウンローダーミドルウェアに環境変数からURLを生成させる必要があります。

Scrapy + Geonode:得られるもの

Scrapyはアプリケーション内のリクエストや接続を処理します。Geonodeはプロキシ接続を処理します。

ジョブに応じて、一般家庭用、ISP、データセンターのプロキシを選択でき、必要に応じてローテーション、スティッキーセッション、ジオターゲティングを利用できます。これにより、プロキシの設定をアプリケーションコードの他の部分から分離できます。

プランはプロキシの種類によって異なり、GB単位で課金されるオプションもあります。

よくある質問

ScrapyはSOCKS5プロキシに対応していますか?

私たちがテストしたバージョンのScrapyでは、SOCKS5を使用するには追加の設定が必要です。

socks5://プロキシをScrapyのデフォルトのHTTPハンドラー経由で渡そうとすると、次のエラーが発生しました:

UnsupportedURLSchemeError("Unsupported scheme: b'socks5'")

そこで、httpx2[socks]をインストールし、Scrapyの実験的なHttpxDownloadHandlerを設定しました。ポート11000でSOCKS5のローテーションプロキシを使用すると、リクエストはHTTP 200で成功し、プロキシのIPアドレスが返されました。このハンドラーは実験的なものであるため、本番環境での使用を推奨するよりも、テスト用途に適しています。

ScrapyでリクエストごとにIPをローテーションさせることはできますか?

はい、Scrapyはローテーションプロキシ経由でリクエストを送信できますが、リクエストごとに異なるIPが割り当てられるとは限りません。

5回のリクエストによるテストでは、2つの異なるIPが確認されました。最初の3つのリクエストは1つのIPを共有し、最後の2つは別のIPを共有しており、テスト中にIPのローテーションが行われたことが確認されました。

無料トライアルはありますか?

はい。Geonodeでは無料トライアルを提供しているため、有料プランに移行する前にScrapyを使ってプロキシを試用することができます。現在の無料トライアルとプランの詳細はこちら。

Scrapyではどこでプロキシを設定すればよいですか?

個別のリクエストについては、request.meta["proxy"] を通じてプロキシを渡してください。

多くのリクエストで同じプロキシ設定が必要な場合は、ダウンローダーミドルウェアを使用することで、プロキシのロジックを一箇所にまとめることができます。私たちのテストでは、Scrapyの組み込み機能であるHttpProxyMiddlewareがリクエストを処理する前に、カスタムミドルウェアがrequest.meta["proxy"]を設定しました。

Scrapyのスパイダーは実行されるのに、リクエストが0件しか送信されないのはなぜですか?

スパイダーが最初のリクエストをどのように生成するかを確認してください。

Scrapy 2.19でのテストでは、レガシーなstart_requests()

メソッドのみを定義した場合、スパイダーはリクエストを1つも送信せずに開始・終了してしまいました。非同期のstart()

メソッドを使用することで、この問題は解決しました:

async def start(self):
    yield scrapy.Request(...)

これは、テスト環境において確認された動作です。