curl_cffi プロキシガイド: セットアップ、認証、ローテーション、非同期
curl_cffi はブラウザのような TLS ハンドシェイクを提供します。プロキシはクリーンな出口IPを提供します。ここでは、これらをどのように組み合わせるか、そしてプロキシ辞書の https:// プレフィックスが ErrCode 35 を引き起こす理由を正確に説明します。
curl_cffi は curl-impersonate フォークの Python バインディングです: それは urllib3 としてではなく、実際のブラウザの TLS/JA3 および HTTP/2 フィンガープリントを再現します。これにより、ブロッキングの一つの軸が修正されます。もう一つは出口IPであり、ここで curl_cffi プロキシが役立ちます — そしてドキュメントが薄い部分です。公式のプロキシセクションは約15行で、2023年2月の GitHub イシューがこのトピックでトップ5にランクインしています。このガイドは全体をカバーします: proxy パラメータ、リクエストスタイルの辞書とその実際のキー名、proxy_auth、セッション、リクエストごとのローテーション、非同期、SOCKS5 — そして検索ボックスに貼り付ける正確なエラーストリング。
curl_cffi プロキシ構文: proxies 辞書より proxy= を優先
curl_cffi は2つの形式を受け入れます。ネイティブなものは単一の proxy= 文字列で、v0.6.0 で追加されました; proxies= 辞書は requests 互換性のために存在し、ドキュメントは本当にスキームごとに異なるプロキシが必要でない限り、単一のパラメータを推奨しています。内部的には同じものに折りたたまれます — proxy="..." は {"all": "..."} になります — そしてモジュールヘルパー、Session、AsyncSession、個別のリクエストで動作します。
# pip install curl_cffi --upgrade (Python 3.10+ since v0.14)
import curl_cffi
PROXY = "http://USER:PASS@gate.quantumproxies.io:PORT"
# Native form — one string, applies to every scheme
r = curl_cffi.get(
"https://tls.browserleaks.com/json",
impersonate="chrome",
proxy=PROXY,
timeout=30,
)
print(r.status_code, r.json()["ja3n_hash"])
# requests-compatible form
r = curl_cffi.get(
"https://httpbin.org/ip",
impersonate="chrome",
proxies={"http": PROXY, "https": PROXY},
timeout=30,
)
print(r.json()) # {'origin': '<proxy exit IP>'}
その辞書について知っておくべき4つのことがあります。READMEからはどれも明らかではありません:
- 有効なキーは
all、http、https、ws、wssです。allはキャッチオールです; WebSocket クライアントにとって WebSocket キーは重要です。 - ホストごとのキーも機能します。
https://api.example.comまたはall://example.comは、そのホストだけを特定のプロキシを通してルーティングします — 難しいドメインを住宅IPを通して送り、残りを直接にするのに便利です。 - 両方を渡すことはできません。 同じ呼び出しで
proxy=とproxies=を使用するとTypeError: Cannot specify both 'proxy' and 'proxies'が発生し、同じチェックがセッションレベルで実行されます。 - 環境変数は尊重されます —
http_proxy、https_proxy、ws_proxy、wss_proxy。企業変数がスクレイパーを乗っ取るときは、trust_env=FalseをSessionに渡します。
インポートに関する一つの注意点: v0.10.0 以降、パッケージは直接呼び出し可能です (curl_cffi.get, curl_cffi.Session)。古いチュートリアルは from curl_cffi import requests を使用していますが、これはまだ機能しますが、実際の requests ライブラリの隣では読みづらく、オンラインのスニペットの半分が異なるプロジェクトのように見える理由を説明しています。
https:// トラップ: ErrCode 35 と WRONG_VERSION_NUMBER
この単一のミスが、他のすべてを合わせたよりも多くの curl_cffi プロキシの質問を生成します。プロジェクトトラッカーの問題 #6 — 2023年2月に同じ日に開かれ閉じられた — はまだページ1にランクインしています。なぜなら、それが生成するエラーが TLS バグのように見えるからです。
# WRONG: this asks curl to open a TLS connection *to the proxy itself*
proxies = {"https": "https://USER:PASS@gate.quantumproxies.io:PORT"}
# Failed to perform, ErrCode: 35, Reason:
# 'error:100000f7:SSL routines:OPENSSL_internal:WRONG_VERSION_NUMBER'
# RIGHT: plain HTTP CONNECT, then the TLS tunnel runs through to the target
proxies = {"https": "http://USER:PASS@gate.quantumproxies.io:PORT"}
# Or skip the dict entirely
proxy = "http://USER:PASS@gate.quantumproxies.io:PORT"
キー名は ターゲット のプロトコルを示し、値は プロキシ に到達する方法を示します。通常の HTTPS-over-HTTP プロキシはプレーンテキストの CONNECT を受け取り、その後暗号化されたトラフィックをそのままトンネルします — したがって、プロキシ URL は取得するすべての URL が HTTPS であっても http:// で始まります。HTTPS-over-HTTPS プロキシは存在しますが、まれであり、ゲートウェイによって明示的にサポートされる必要があります。Requests は同じ失敗をはるかに助けになる形で表現します — あなたのプロキシは HTTP のみを使用しているように見え、HTTPS ではない — これが、同一の設定が curl_cffi 特有のバグのように見える理由です。最近のバージョンは警告を発し、問題 #6 にリンクしますが、それはあくまで警告です: リクエストはまだ失敗します。
認証: URL クレデンシャルまたは proxy_auth
認証されたゲートウェイは通常の埋め込み形式、http://USER:PASS@host:port を受け入れますが、通常の注意点があります: パスワードにエスケープされていない @、:、/ が含まれると、URL が誤った場所で分割され、デッドプロキシのように見える認証失敗が発生します。curl_cffi は requests が提供しないエスケープハッチを提供します — proxy_auth タプルを libcurl に渡し、ユーザー名とパスワードオプションを別々にするので、エンコーディングはまったく関与しません。
import curl_cffi
from urllib.parse import quote
# Option A — credentials in the URL, password URL-encoded
pw = quote("p@ss:word", safe="")
r = curl_cffi.get(
"https://httpbin.org/ip",
proxy=f"http://USER:{pw}@gate.quantumproxies.io:PORT",
impersonate="chrome",
timeout=30,
)
# Option B — keep credentials out of the URL entirely
r = curl_cffi.get(
"https://httpbin.org/ip",
proxy="http://gate.quantumproxies.io:PORT",
proxy_auth=("USER", "PASS"),
impersonate="chrome",
timeout=30,
)
print(r.json())
第三のオプションはこのバグのクラスを完全に取り除きます: IP ホワイトリスト化です。すべての QuantumProxies 住宅プラン では、ユーザー:パスを送信する代わりにサーバーの IP を認証できますので、プロキシ URL は単なる http://gate.quantumproxies.io:PORT になります — エンコードするものはなく、ソースツリーに秘密はありません。クレデンシャル自体が拒否されている場合は、407 Proxy Authentication Required のすべての原因 に関するガイドが残りをカバーします。

セッション、クッキー、クレデンシャル再利用の詳細
Session はクッキー、接続プーリング、デフォルトを一箇所に保持します。これはマルチステップの何かに必要なものです。impersonate と proxy を一度設定すると、すべてのリクエストがそれを継承します:
from curl_cffi import Session
with Session(
impersonate="chrome",
proxy="http://USER-session-a1b2:PASS@gate.quantumproxies.io:PORT",
timeout=30,
retry=3,
) as s:
s.get("https://httpbin.org/cookies/set/foo/bar")
r = s.get("https://httpbin.org/cookies")
print(r.json(), s.cookies.get_dict())
2つの動作は特筆に値します。まず、プロキシが設定されると、curl_cffi は libcurl の proxy-credential-no-reuse オプションをオンにします: プロキシのユーザー名が変更されると新しい接続が強制され、TLS セッションキャッシュはプロキシアドレスに基づいてキーが設定されるため、以前の出口IPが再利用されたセッションを通じて後のリクエストに漏れることはありません。ほとんどの回転ゲートウェイが行うように、ユーザー名にスティッキーセッションIDをエンコードする場合、その隔離を無料で得ることができます。第二に、retry (int または curl_cffi.requests の RetryStrategy で遅延、バックオフ、ジッターを伴う) はトランスポート例外でのみ再実行されます。403 または 429 を urllib3 の status_forcelist のように再試行することはありません — そのループはまだ自分で書く必要があります。互換性ドキュメントはリトライをサポートされていないとリストしていますが、これは古い情報です: パラメータは v0.15.0 で導入されました。
リクエストごとのローテーションと非同期
curl_cffi はリクエストごとにプロキシローテーションを伴う asyncio を宣伝しており、それは文字通りです: 個々の呼び出しでの proxy= 引数はセッションが保持するものを上書きします。それを活用するためにプロキシリストを必要とすることはめったにありません — 回転ゲートウェイは接続ごとに新しい出口サーバーを割り当てるので、1つのエンドポイントと同時実行性だけで既にローテーションです。制御が必要な場合 (ワーカーごと、アカウントごと、カートごとに安定したIPが必要な場合)、ユーザー名にセッショントークンを入れ、ゲートウェイにその出口を固定させます。
import asyncio
from curl_cffi import AsyncSession
GATE = "gate.quantumproxies.io:PORT"
URLS = ["https://httpbin.org/ip"] * 20
async def fetch(session, url, worker):
# one sticky exit IP per worker; drop the -session- suffix for full rotation
proxy = f"http://USER-session-{worker}:PASS@{GATE}"
r = await session.get(url, proxy=proxy, timeout=30)
return r.status_code, r.json()["origin"]
async def main():
async with AsyncSession(impersonate="chrome", max_clients=10) as s:
return await asyncio.gather(
*(fetch(s, u, i % 5) for i, u in enumerate(URLS))
)
for status, ip in asyncio.run(main()):
print(status, ip)
max_clients はプール内の同時 curl ハンドルを制限します (デフォルトは10)、したがってそれが実際の同時実行性のダイヤルです — 無制限の gather にセマフォを取り付けるのが通常の間違いです。同じサイズ設定のロジックは任意の非同期クライアントに適用されます。これについては httpx と aiohttp を使用した Python 非同期スクレイピング でカバーしました。リクエストごとにローテーションするか、セッションを固定するかは、サイトがリクエスト間で状態を追跡するかどうかに依存します; トレードオフは スティッキーセッション対回転プロキシ にあります。

SOCKS5、HTTP/3 と安全スイッチ
SOCKS は追加インストールを必要としません — libcurl がコンパイルされているので、requests のように [socks] エクストラを覚える必要はありません。socks5h://USER:PASS@gate.quantumproxies.io:PORT を使用します: h は DNS 解決をプロキシに押し付け、ネットワークからのリークを防ぎ、出口の場所から地理的に制限されたホスト名を解決します。curl_cffi は socks プレフィックスを検出し、SOCKS プロトコルがそれ自体で処理するため、HTTP トンネリングフラグをスキップします。ここでのすべてのプランは同じゲートウェイで HTTP と SOCKS5 エンドポイント を公開しているので、切り替えはスキームの交換であり、新しい注文ではありません。
- プロキシ経由の HTTP/3 は v0.15.0 で http/3 フィンガープリントと共に登場しましたが、UDP を話す SOCKS5 サーバーが必要で、通常の HTTP ゲートウェイではありません。ターゲットが QUIC を報酬としている場合に限られます。
- SSRF 強化。 同じリリースでアドバイザリが発行されました: 他の人が提供した URL をフェッチする場合、リダイレクトが内部ネットワークに歩かれる可能性があります。
allow_redirects="safe"を設定するか、リダイレクトをオフにします。 - デバッグ。 v0.15 では CLI が出荷されました:
curl-cffi get tls.browserleaks.com/json --impersonate chromeは、擬装が着地しているかどうかをプロキシを責める前に1行で教えてくれます。
curl_cffi とプロキシが十分な場合
予想以上に多いです。ターゲットが内部 API から JSON を提供するか、サーバーレンダリングされた HTML を提供し、唯一の障害がフィンガープリントチェックである場合、マッチしたハンドシェイクと住宅の出口で、ブラウザのコストと遅延の一部でそれをクリアします。プロジェクトの FAQ は天井について率直です: フィンガープリントは、IP 品質、リクエストレート、JavaScript チェックと並んで、いくつかの要因のうちの1つであり、より高い保護層はより良いプロキシプールと実際のブラウザオートメーションの両方を必要とします。擬装が正しく設定されていてもブロックされる場合、残りの変数はほぼ常に出口IPです — それを5分で隔離することは curl_cffi vs requests の主題です。どちらも実行したくない場合は、Scraper API がフィンガープリント、プロキシ、オプションの JS レンダリングを1つの呼び出しで処理します。
よくある質問
curl_cffi でプロキシをどのように使用しますか?
任意のリクエストメソッド、セッション、または非同期セッションに proxy="http://USER:PASS@host:port" を渡します。requests スタイルの proxies={"http": ..., "https": ...} 辞書も機能しますが、プロジェクトはスキームごとに異なるプロキシが必要でない限り、単一のパラメータを推奨しています。両方を渡すと TypeError が発生します。
なぜ curl_cffi は ErrCode 35 WRONG_VERSION_NUMBER を投げるのですか?
プロキシ URL が https:// で始まるからです。標準のプロキシはプレーンテキストの CONNECT リクエストを期待し、その後 TLS をトンネルします; https:// プレフィックスは curl にプロキシ自体と TLS ハンドシェイクしようとさせ、プロキシはプレーン HTTP で応答します。値を http:// に変更してください — https キーはターゲットを指し、ホップではありません。
curl_cffi は SOCKS5 プロキシをサポートしていますか?
はい、ネイティブに — libcurl がバンドルされているので、インストールするオプションのエクストラはありません。ホスト名があなたのマシンではなくプロキシによって解決されるように socks5h:// スキームを使用します。SOCKS4、SOCKS4a、プレーン socks5:// も受け入れられます; ライブラリはスキームが socks で始まるプロキシの HTTP トンネリングをスキップします。
curl_cffi はリクエストごとにプロキシをローテーションできますか?
はい。個々の呼び出しでの proxy= 引数は、AsyncSession 内を含め、セッションのデフォルトを上書きします。これは README がリクエストごとのローテーションを伴う asyncio を意味するものです。回転ゲートウェイを使用すると、通常はまったくロジックが必要ありません: 同じエンドポイントが接続ごとに異なる出口IPを提供します。
curl_cffi は Cloudflare をバイパスできますか?
場合によります。TLS と HTTP/2 のフィンガープリントの兆候を取り除き、基本的な保護レベルには十分です。JavaScript チャレンジを実行したり、Turnstile を解決したり、評判データベースで既にフラグが立てられたデータセンターIPを修復することはできません。擬装を3つの要件の1つとして扱い、答えではありません。
全体の構成はその評判よりも小さいです: 1つの proxy 文字列、セッションに1度設定された impersonate、すべての呼び出しにタイムアウト、URL エンコードされたか proxy_auth タプルとして渡されたクレデンシャル。これらを正しく設定し、残りの変数は IP 品質です — フラグが立てられたデータセンターアドレスからの完璧な Chrome ハンドシェイクは依然としてフラグが立てられたデータセンターアドレスです。JA3 と JA4 フィンガープリント の内訳は、2つのチェックが独立している理由を説明します。