各 Python ThreadPoolExecutor ジョブに URL とプロキシを割り当てる
ワーカーが共有の可変な選択状態を奪い合うのではなく、Python リクエストジョブを送信する前にプロキシを割り当てます。
プールの map はワーカーに一度に 1 つの項目を渡します。その項目を、URL と選択済みプロキシを含む完全なジョブにしてください。ワーカーが変化するグローバルリストから経路を推測しないようにするためです。
有限個の urls には、検証済みプロキシ URL の空でないリストを指定します。公開 HTTP 候補はHTTP プロキシリストで入手できます:
from concurrent.futures import ThreadPoolExecutor
from itertools import cycle
import requests
def fetch(job):
url, proxy_url = job
proxies = {"http": proxy_url, "https": proxy_url}
with requests.get(url, proxies=proxies, timeout=(5, 15)) as response:
response.raise_for_status()
return url, response.text
if not proxy_urls:
raise ValueError("No proxy endpoints were supplied")
jobs = zip(urls, cycle(proxy_urls))
with ThreadPoolExecutor(max_workers=5) as executor:
for url, body in executor.map(fetch, jobs):
handle_result(url, body)urls、proxy_urls、handle_result はアプリケーションが提供します。コーディネーターはエンドポイントを繰り返しの順序で割り当て、各ワーカーは 1 つの固定ペアを受け取ります。結果を反復すると、ワーカーの例外も表面化します。
5 つのワーカーが制限するのはアクティブなジョブであり、プロキシごとのアクティブなジョブではありません。リストに 2 つのエンドポイントがあれば、複数のジョブが同じエンドポイントを同時に使えます。必要な場合はエンドポイントごとの容量ルールを別途追加してください。エンドポイント URL ごとに 1 つのアクティブなジョブにするには、同期キューのリースが各エントリを予約して返せます。
再試行は同じ URL に対して新しい上限付きの試行を作るべきです。共有リストからエントリを削除する再帰的な再試行呼び出しは避けてください。別のワーカーがそこから選択している可能性があり、使い果たしたリストにも明示的な結果が必要です。