クイックアンサー
Seleniumでユーザー名とパスワード付きプロキシを使うには?
Proxy-Authorizationヘッダーを追加する小さなローカルフォワーダーを起動し、Chromeに--proxy-server=http://127.0.0.1:8899で設定してください。Chromeはそのフラグ内の認証情報を無視し、Seleniumにはプロキシパスワード用のポータブルなオプションがありません。CrawlRelayのレジデンシャルプロキシはgw.crawlrelay.com:7777でこう動作し、$0.50/GBから購入可能です。暗号通貨で支払い、KYC不要。
Seleniumセットアップ概要
| なぜフォワーダーが必要か | Chromeの--proxy-serverフラグはユーザー名やパスワードを受け付けない |
|---|---|
| フォワーダー | 127.0.0.1:8899で待ち受け、Proxy-Authorizationを追加しgw.crawlrelay.com:7777へ中継 |
| Chromeオプション | --proxy-server=http://127.0.0.1:8899 |
| ローテーション | 新しいCONNECTトンネルは新規接続で通常新しい出口を意味するため、セッションIDを追加して1つのIPに固定する |
| より簡単な代替策 | Playwrightはユーザー名とパスワードを直接受け取ります |
ローカルフォワーダーはどう動くの?
ブラウザのプロキシリクエストを受け取り、認証情報を含むヘッダーを1つ挿入し、両方向にバイトを転送します。HTTPSサイトの場合、ブラウザがCONNECT host:443を送信、ゲートウェイが200 Connection establishedで応答し、TLSがChromeとサイト間でエンドツーエンドに動作します。フォワーダーはページ内容を平文で見ることはありません。
この最小限のバージョンは、接続ごとに1つのCONNECTトンネルを持つHTTPSサイトに対応し、ほぼすべてのサイトをカバーします。127.0.0.1にバインドして他のマシンが認証情報を使えないようにしておきましょう。
import asyncio
import base64
import os
UPSTREAM = ("gw.crawlrelay.com", 7777)
USER = os.environ.get("CRAWLRELAY_USER", "USERNAME-country-us")
PASSWORD = os.environ.get("CRAWLRELAY_PASSWORD", "PASSWORD")
AUTH = b"Proxy-Authorization: Basic " + base64.b64encode(("%s:%s" % (USER, PASSWORD)).encode())
async def pipe(reader, writer):
try:
while True:
data = await reader.read(65536)
if not data:
break
writer.write(data)
await writer.drain()
except ConnectionError:
pass
finally:
writer.close()
async def handle(client_reader, client_writer):
try:
head = await client_reader.readuntil(b"\r\n\r\n") # request line and headers from the browser
except asyncio.IncompleteReadError:
client_writer.close()
return
lines = head.split(b"\r\n")
lines.insert(1, AUTH) # add the credentials right after the request line
up_reader, up_writer = await asyncio.open_connection(*UPSTREAM)
up_writer.write(b"\r\n".join(lines))
await up_writer.drain()
await asyncio.gather(pipe(client_reader, up_writer), pipe(up_reader, client_writer))
async def main():
server = await asyncio.start_server(handle, "127.0.0.1", 8899)
async with server:
await server.serve_forever()
if __name__ == "__main__":
asyncio.run(main())Seleniumをフォワーダーに向けるには?
1つの端末でforwarder.pyを起動し、ローカルプロキシのアドレスを指定してSeleniumスクリプトを実行します。Selenium 4.6以降に組み込まれたSelenium Managerが対応するChromeDriverを自動でダウンロードしてくれるので、他にインストールは不要です。
from selenium import webdriver
from selenium.webdriver.common.by import By
options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://127.0.0.1:8899") # the local forwarder
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)
try:
driver.set_page_load_timeout(60)
driver.get("https://api.ipify.org")
print("exit IP:", driver.find_element(By.TAG_NAME, "body").text)
finally:
driver.quit()SeleniumセッションごとにIPを変える、またはページごとに新しいIPを使うには?
フォワーダーは与えられたユーザー名をそのまま送るため、セッションの挙動はユーザー名で制御します:
- 接続ごとにローテーション: セッション部分(
USERNAME-country-us)を省略。Chromeはページごとに複数接続を開くため、単一ページでも複数の出口IPを使えます。 - Seleniumセッションごとに1IP: フォワーダー起動前に
CRAWLRELAY_USERをUSERNAME-country-us-session-run42-ttl-30に設定。接続は最大30分同じIP経由しますが、早く変更されることもあります。 - 複数セッション並行: 各セッションで別々のローカルポート(例:8899、8900)でフォワーダーを実行し、各WebDriverに専用ポートを割り当てます。
selenium-wireやブラウザ拡張はどう?
selenium-wireは2024年1月に作者がアーカイブし更新されていません。プロキシ認証を通信傍受で追加する人気パッケージでした。ブラウザ拡張でプロキシの認証要求に応答する方法もありますが、各プロファイルにパッケージ化して読み込ませる必要があります。上述のフォワーダーは依存なしで、Seleniumが動かせる任意のブラウザに対応します。新規プロジェクトなら、Playwrightのほうがもっと簡単で、ユーザー名とパスワードを直接受け取ります。
Seleniumとプロキシ:よくある質問
なぜSeleniumのChromeでプロキシのログインポップアップが出るの?
プロキシが認証情報を求めたのにChromeに設定がなかったためです。Chromeの--proxy-serverフラグはホストとポートだけ受け取ります。ヘッドレスでも同様にERR_TUNNEL_CONNECTION_FAILEDが出ます。認証情報を追加するローカルフォワーダーを使うか、ユーザー名・パスワード対応のPlaywrightに切り替えましょう。
フォワーダーはスクレイピングを遅くする?
ほとんどしません。ローカルソケット2つとリモート1つの間でバイトをコピーするだけで復号化は行いません。ページの読み込み時間はレジデンシャルプロキシの出口と対象サイト次第であって、同一マシン上のフォワーダーの影響はありません。
SeleniumでChromeの代わりにFirefoxは使える?
使えます。FirefoxOptionsでFirefoxのプロキシ設定をして、network.proxy.typeを1、network.proxy.httpとnetwork.proxy.sslをポート8899で127.0.0.1に設定してください。フォワーダーを通す形にしないと、Firefoxの認証ダイアログはSeleniumで信頼性高く対応できません。
フォワーダー内のパスワードは安全?
例のようにフォワーダーが127.0.0.1で待ち受けている間は機械内に留まります。環境変数から読み込み、絶対にコミットせず、各スクレイパーごとにトラフィック上限付きサブユーザーを使い、漏洩してもプラン全体をダメにしない運用を推奨します。
Seleniumでレジデンシャルプロキシの出口を使う
テスト用に$1.50を1 GB、$0.50/GBを50 GBから取得。