プロキシが常にバンされる場合:診断と問題解決の完全ガイド
プロキシの継続的なブロックは、スクレイピング、自動化、複数アカウント管理時の最も一般的な問題の1つです。この記事では、なぜこれが起こるのか、そして奇跡を期待してプロバイダーを無限に変更するのではなく、体系的に問題を解決する方法について説明します。
実際にプロキシがバンされる理由
解決策を探す前に、ブロックのメカニズムを理解する必要があります。最新の不正検出システムは多層防御を使用しており、プロキシのバンはその結果に過ぎず、原因ではありません。これらのシステムがどのように機能するかを理解することで、効果的な回避戦略を構築できます。
IP評判とブラックリスト
各IPアドレスには、その使用履歴に基づいて形成される評判があります。アドレスが以前スパム、DDoS攻撃、または大規模スクレイピングに使用されていた場合、Spamhaus、SORBS、または特定のサービスの独自リストなどのデータベースに登録されます。そのようなIPを通じて接続すると、システムはすぐに疑いを持ちます。
データセンタープロキシは特にこの問題の影響を受けやすいです。IP範囲全体が「ホスティング」とマークされ、そこからのトラフィックは自動的に高度なチェックを受けます。Amazon AWS、Google Cloud、DigitalOcean — これらのIP範囲はよく知られており、予防的にブロックされることが多いです。
IPQualityScore、Scamalytics、AbuseIPDBなどのサービスを通じてIP評判を確認できます。プロキシのfraud scoreが75を超える場合、これが問題です — プロバイダーを変更するか、別のプロキシタイプを選択してください。
リクエストパターン
人間は1秒間に100リクエストを送信しません。人間は完璧な周期性で2秒ごとにページを遷移しません。人間は画像、CSS、JavaScriptを無視して、HTMLだけをリクエストしません。不正検出システムはまさにこれらのパターンを分析し、「人間的」な行動からの逸脱は、ブロックのリスクを高めます。
リクエスト間の時間統計は特に有用です。安定した間隔は自動化の明らかな兆候です。ランダムな遅延を追加する(例えば1~5秒)ことで、検出の可能性を大幅に減らします。
メタデータの不一致
User-AgentがWindows上のChromeを示しているのに、HTTPヘッダーがPython requestsの特性を示している場合 — これは赤旗です。IPアドレスがドイツに地理的に位置しているのに、ブラウザ言語設定がロシア語を示している場合 — もう1つの赤旗です。JavaScriptのタイムゾーンがIP地理と一致しない場合 — 3番目の赤旗です。
このような不一致の蓄積により、システムは接続を疑わしいものとして分類し、CAPTCHAから完全なIPブロックまでの保護措置を適用します。
ブラウザフィンガープリント
最新の保護システムはブラウザの数十のパラメータを収集します:画面解像度、インストール済みフォント、プラグイン、WebGLレンダリング、オーディオコンテキストなど。これらのパラメータの組み合わせは、CookieなしでもユーザーをIPアドレスが変わっても識別できるユニークな「フィンガープリント」を作成します。
プロキシを変更しても、フィンガープリントが同じままの場合、システムは同じユーザーであることを理解します。1つのフィンガープリントが短時間に数百の異なるIPから表示される場合 — これは自動化の明らかな兆候です。
診断:ブロックの原因を理解する
ブロックの原因を推測する前に、診断を実施してください。これにより、数時間の試行錯誤が節約され、問題の実際の原因を見つけるのに役立ちます。診断への体系的なアプローチが、効果的なソリューションの鍵です。
ステップ1:プロキシ自体を確認する
メインスクリプトとは独立して、プロキシの基本的な機能を確認することから始めてください:
import requests
proxy = {
"http": "http://user:pass@proxy-server:port",
"https": "http://user:pass@proxy-server:port"
}
# プロキシの基本的な機能確認
try:
response = requests.get("https://httpbin.org/ip", proxies=proxy, timeout=10)
print(f"プロキシ経由のIP: {response.json()['origin']}")
except Exception as e:
print(f"接続エラー: {e}")
# 実IPの漏洩確認
response = requests.get("https://browserleaks.com/ip", proxies=proxy)
# 実IPと比較してください
プロキシが単純なリクエストでも機能しない場合 — 問題はプロキシ自体または認証情報にあります。接続形式の正確性、プロバイダーの残高、制限を確認してください。
ステップ2:IP評判を確認する
複合的な評価のために複数のサービスを使用してください:
# プロキシIPを取得
proxy_ip = requests.get("https://api.ipify.org", proxies=proxy).text
# これらのサービスで確認してください:
# https://www.ipqualityscore.com/free-ip-lookup-proxy-vpn-test
# https://scamalytics.com/ip/{proxy_ip}
# https://www.abuseipdb.com/check/{proxy_ip}
# https://whatismyipaddress.com/ip/{proxy_ip}
print(f"上記のサービスでIP {proxy_ip} を確認してください")
次の指標に注意してください:fraud score(50未満であるべき)、IPタイプ(データセンターより住宅用が良い)、ブラックリストへの登録。IPがVPN/Proxyとマークされている場合 — 多くのサイトは最初から疑いを持ちます。
ステップ3:問題を分離する
異なるターゲットサイトで同じプロキシを試してください。すべてでブロックされる場合 — 問題はプロキシまたは設定にあります。特定のサイトでのみブロックされる場合 — 問題はそのサイトの保護またはあなたの行動にあります。
また、1つのサイトで異なるプロキシを試してください。すべてがブロックされる場合 — 問題はプロキシではなく、スクリプト、フィンガープリント、または行動パターンにあります。これは多くの人が見落とす重要なテストです。
ステップ4:サーバー応答の分析
異なるタイプのブロックは異なる方法で現れます。それらを区別することを学んでください:
def analyze_response(response):
status = response.status_code
if status == 403:
print("アクセス禁止 — IPがブラックリストに登録されている可能性")
elif status == 429:
print("リクエストが多すぎます — 頻度を下げてください")
elif status == 503:
print("サービス利用不可 — DDoS保護の可能性")
elif status == 407:
print("プロキシ認証が必要 — 認証情報を確認してください")
elif "captcha" in response.text.lower():
print("CAPTCHAが検出されました — ボット疑いあり")
elif "blocked" in response.text.lower():
print("明示的なブロック — IPを変更して方法を見直してください")
elif len(response.text) < 1000:
print("疑わしく短い応答 — スタブの可能性")
else:
print(f"ステータス {status}、応答長: {len(response.text)}")
適切なローテーション:頻度、ロジック、実装
プロキシローテーションは単に「より頻繁にIPを変更する」ことではありません。不適切なローテーションは、その不在よりも害をもたらす可能性があります。異なる戦略と、それらをいつ適用するかについて考えてみましょう。
戦略1:リクエスト数に基づくローテーション
シンプルなアプローチ — 一定数のリクエスト後にIPを変更します。セッション性が不要なスクレイピングに適しています:
import random
class ProxyRotator:
def __init__(self, proxy_list, requests_per_proxy=50):
self.proxies = proxy_list
self.requests_per_proxy = requests_per_proxy
self.current_proxy = None
self.request_count = 0
def get_proxy(self):
if self.current_proxy is None or self.request_count >= self.requests_per_proxy:
# リクエスト数にランダム性を追加
self.requests_per_proxy = random.randint(30, 70)
self.current_proxy = random.choice(self.proxies)
self.request_count = 0
self.request_count += 1
return self.current_proxy
# 使用方法
rotator = ProxyRotator(proxy_list)
for url in urls_to_scrape:
proxy = rotator.get_proxy()
response = requests.get(url, proxies={"http": proxy, "https": proxy})
リクエスト数の固定値(例えば正確に50)は検出可能なパターンです。ランダムな範囲を使用すると、動作がより予測不可能になります。
戦略2:時間ベースのローテーション
セッション性が重要なタスク(例えばアカウント操作)の場合、IPを時間に基づいてローテーションする方が良いです:
import time
import random
class TimeBasedRotator:
def __init__(self, proxy_list, min_minutes=10, max_minutes=30):
self.proxies = proxy_list
self.min_seconds = min_minutes * 60
self.max_seconds = max_minutes * 60
self.current_proxy = None
self.rotation_time = 0
def get_proxy(self):
current_time = time.time()
if self.current_proxy is None or current_time >= self.rotation_time:
self.current_proxy = random.choice(self.proxies)
# 次のローテーションまでのランダムな間隔
interval = random.randint(self.min_seconds, self.max_seconds)
self.rotation_time = current_time + interval
print(f"新しいプロキシ、次のローテーションは{interval//60}分後")
return self.current_proxy
戦略3:アカウント用のスティッキーセッション
複数のアカウントで作業する場合、各アカウントが一定のIPを使用することが重要です。ログイン済みアカウントのIP変更は確実にバンにつながります:
class AccountProxyManager:
def __init__(self, proxy_pool):
self.proxy_pool = proxy_pool
self.account_proxies = {} # account_id -> proxy
self.used_proxies = set()
def get_proxy_for_account(self, account_id):
# アカウントに既にプロキシが割り当てられている場合は返す
if account_id in self.account_proxies:
return self.account_proxies[account_id]
# 利用可能なプロキシを見つける
available = [p for p in self.proxy_pool if p not in self.used_proxies]
if not available:
raise Exception("新しいアカウント用の利用可能なプロキシがありません")
proxy = random.choice(available)
self.account_proxies[account_id] = proxy
self.used_proxies.add(proxy)
return proxy
def release_account(self, account_id):
"""アカウント削除時にプロキシを解放"""
if account_id in self.account_proxies:
proxy = self.account_proxies.pop(account_id)
self.used_proxies.discard(proxy)
# 使用方法
manager = AccountProxyManager(residential_proxy_list)
for account in accounts:
proxy = manager.get_proxy_for_account(account.id)
# このアカウントのすべてのアクションは1つのIPを通じて実行
戦略4:適応型ローテーション
最も高度なアプローチ — ターゲットサイトからのシグナルに応じてプロキシを変更します:
class AdaptiveRotator:
def __init__(self, proxy_list):
self.proxies = proxy_list
self.current_proxy = random.choice(proxy_list)
self.proxy_scores = {p: 100 for p in proxy_list} # プロキシの初期「健全性」
def get_proxy(self):
return self.current_proxy
def report_result(self, success, response_code=200):
"""各リクエスト後に呼び出される"""
if success and response_code == 200:
# 成功したリクエスト — スコアをわずかに上げる
self.proxy_scores[self.current_proxy] = min(100,
self.proxy_scores[self.current_proxy] + 1)
elif response_code == 429:
# レート制限 — スコアを大幅に下げてローテーション
self.proxy_scores[self.current_proxy] -= 30
self._rotate()
elif response_code == 403:
# バン — スコアをリセットしてローテーション
self.proxy_scores[self.current_proxy] = 0
self._rotate()
elif response_code == 503:
# 保護の可能性 — スコアを下げてローテーション
self.proxy_scores[self.current_proxy] -= 20
self._rotate()
def _rotate(self):
# スコアが最も高いプロキシを選択
available = [(p, s) for p, s in self.proxy_scores.items() if s > 20]
if not available:
# すべてのプロキシが「殺された」 — スコアをリセット
self.proxy_scores = {p: 50 for p in self.proxies}
available = list(self.proxy_scores.items())
# スコアに基づいた加重選択
self.current_proxy = max(available, key=lambda x: x[1])[0]
print(f"スコア{self.proxy_scores[self.current_proxy]}のプロキシにローテーション")
ブラウザフィンガープリントとブロックの役割
フィンガープリントはブラウザの特性の集合であり、Cookieなしでもユーザーを識別できます。IPを変更しても、フィンガープリントが同じままの場合、保護システムは同じユーザーであることを理解します。
フィンガープリントの構成
最新のフィンガープリントには数十のパラメータが含まれます。主なカテゴリは次のとおりです:
| カテゴリ | パラメータ | 識別での重要度 |
|---|---|---|
| User-Agent | ブラウザ、バージョン、OS | 中程度 |
| スクリーン | 解像度、色深度、ピクセル比 | 中程度 |
| フォント | インストール済みフォントのリスト | 高い |
| WebGL | レンダラー、ベンダー、レンダリングハッシュ | 非常に高い |
| Canvas | 描画された画像のハッシュ | 非常に高い |
| Audio | AudioContextフィンガープリント | 高い |
| タイムゾーン | タイムゾーン、オフセット | 中程度 |
| 言語 | navigator.languages | 中程度 |
| プラグイン | navigator.plugins | 低い(最新ブラウザ) |
フィンガープリントとIPの一貫性
フィンガープリントがIP地理と一致することが重要です。プロキシがドイツにある場合、フィンガープリントはドイツのユーザーのように見える必要があります:
// 不一致の例(悪い):
// IP:ドイツ
// タイムゾーン:America/New_York
// 言語:["ru-RU", "ru"]
// これは疑いを引き起こします
// 一貫したフィンガープリント(良い):
// IP:ドイツ
// タイムゾーン:Europe/Berlin
// 言語:["de-DE", "de", "en-US", "en"]
フィンガープリント管理ツール
本格的な作業には、専門的なツールを使用してください:
Stealth付きPlaywright:
from playwright.sync_api import sync_playwright
from playwright_stealth import stealth_sync
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={"server": "http://proxy:port", "username": "user", "password": "pass"}
)
context = browser.new_context(
viewport={"width": 1920, "height": 1080},
locale="de-DE",
timezone_id="Europe/Berlin",
geolocation={"latitude": 52.52, "longitude": 13.405},
permissions=["geolocation"]
)
page = context.new_page()
stealth_sync(page) # ステルスパッチを適用
page.goto("https://target-site.com")
puppeteer-extra付きPuppeteer:
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
const browser = await puppeteer.launch({
args: [`--proxy-server=http://proxy:port`]
});
const page = await browser.newPage();
// タイムゾーンをオーバーライド
await page.evaluateOnNewDocument(() => {
Object.defineProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', {
value: function() {
return { timeZone: 'Europe/Berlin' };
}
});
});
アンチディテクトブラウザ
アカウント作業には、アンチディテクトブラウザ(Multilogin、GoLogin、Dolphin Antyなど)がよく使用されます。これらは、ユニークなフィンガープリントを持つ分離されたプロファイルを作成できます。各プロファイルには独自のパラメータセット、Cookie、localStorage — 完全に分離された環境があります。
アンチディテクトの利点は、フィンガープリント問題を「すぐに」解決することです。欠点は、コストと自動化の複雑さです(ただし、多くはAPIを持っています)。
行動パターン:ボットに見えないようにする
完璧なフィンガープリントと清潔なIPがあっても、非人間的な行動によってバンを受ける可能性があります。最新のシステムは技術パラメータだけでなく、サイトとの相互作用パターンも分析します。
時間遅延
人間は一定の間隔でリクエストを送信しません。正規分布を使用してランダムな遅延を追加してください:
import random
import time
import numpy as np
def human_delay(min_sec=1, max_sec=5, mean=2.5):
"""
人間的な遅延を生成します。
対数正規分布を使用 —
ほとんどの遅延は短いですが、時々長い遅延があります。
"""
delay = np.random.lognormal(mean=np.log(mean), sigma=0.5)
delay = max(min_sec, min(max_sec, delay))
return delay
def human_typing_delay():
"""キー入力間の遅延"""
return random.uniform(0.05, 0.25)
# 使用方法
for url in urls:
response = requests.get(url, proxies=proxy)
process(response)
time.sleep(human_delay()) # リクエスト間のランダムな一時停止
ナビゲーションの模倣
人間は直接リンクから商品ページに移動しません。ホームページに移動し、検索を使用し、カテゴリを閲覧します。このパスを模倣してください:
async def human_like_navigation(page, target_url):
"""ターゲットページへの人間的なナビゲーションを模倣"""
# 1. ホームページに移動
await page.goto("https://example.com")
await page.wait_for_timeout(random.randint(2000, 4000))
# 2. ときどきホームページをスクロール
if random.random() > 0.5:
await page.evaluate("window.scrollBy(0, 300)")
await page.wait_for_timeout(random.randint(1000, 2000))
# 3. 検索またはナビゲーションを使用
if random.random() > 0.3:
search_box = await page.query_selector('input[type="search"]')
if search_box:
await search_box.type("search query", delay=100)
await page.keyboard.press("Enter")
await page.wait_for_timeout(random.randint(2000, 4000))
# 4. ターゲットページに移動
await page.goto(target_url)
# 5. 人間的にページをスクロール
await human_scroll(page)
async def human_scroll(page):
"""人間的なスクロールを模倣"""
scroll_height = await page.evaluate("document.body.scrollHeight")
current_position = 0
while current_position < scroll_height * 0.7: # 最後まで行かない
scroll_amount = random.randint(200, 500)
await page.evaluate(f"window.scrollBy(0, {scroll_amount})")
current_position += scroll_amount
await page.wait_for_timeout(random.randint(500, 1500))
マウスの動き
一部のシステムはマウスの動きを追跡します。ポイントAからポイントBへの直線移動はボットの兆候です。人間はマイクロ補正を伴う曲線でマウスを動かします:
import bezier
import numpy as np
def generate_human_mouse_path(start, end, num_points=50):
"""
ベジェ曲線を使用して、人間的なマウスパスを生成します
わずかなノイズを追加します。
"""
# ベジェ曲線の制御点
control1 = (
start[0] + (end[0] - start[0]) * random.uniform(0.2, 0.4) + random.randint(-50, 50),
start[1] + (end[1] - start[1]) * random.uniform(0.2, 0.4) + random.randint(-50, 50)
)
control2 = (
start[0] + (end[0] - start[0]) * random.uniform(0.6, 0.8) + random.randint(-50, 50),
start[1] + (end[1] - start[1]) * random.uniform(0.6, 0.8) + random.randint(-50, 50)
)
# ベジェ曲線を作成
nodes = np.asfortranarray([
[start[0], control1[0], control2[0], end[0]],
[start[1], control1[1], control2[1], end[1]]
])
curve = bezier.Curve(nodes, degree=3)
# 曲線上のポイントを生成
points = []
for t in np.linspace(0, 1, num_points):
point = curve.evaluate(t)
# マイクロノイズを追加
x = point[0][0] + random.uniform(-2, 2)
y = point[1][0] + random.uniform(-2, 2)
points.append((x, y))
return points
async def human_click(page, selector):
"""人間的なマウス動きでセレクタをクリック"""
element = await page.query_selector(selector)
box = await element.bounding_box()
# ターゲットポイント — 中心ではなく、要素内のランダムなポイント
target_x = box['x'] + random.uniform(box['width'] * 0.2, box['width'] * 0.8)
target_y = box['y'] + random.uniform(box['height'] * 0.2, box['height'] * 0.8)
# 現在のマウス位置(またはランダムな開始位置)
start_x = random.randint(0, 1920)
start_y = random.randint(0, 1080)
# パスを生成
path = generate_human_mouse_path((start_x, start_y), (target_x, target_y))
# パスに沿ってマウスを動かす
for x, y in path:
await page.mouse.move(x, y)
await page.wait_for_timeout(random.randint(5, 20))
# クリック前の小さな一時停止
await page.wait_for_timeout(random.randint(50, 150))
await page.mouse.click(target_x, target_y)
リソースの読み込み
実際のブラウザはHTMLだけでなく、CSS、JavaScript、画像、フォントも読み込みます。requestsを使用してHTMLだけをリクエストする場合は疑わしいです。headless-ブラウザを使用する場合、この問題は自動的に解決されますが、HTTPクライアントを使用する場合は、このポイントを考慮する必要があります。
タスクに応じたプロキシタイプの選択
異なるプロキシタイプには異なる特性があり、異なるタスクに適しています。不適切な選択は、ブロックの一般的な原因です。
データセンタープロキシ
データセンタープロキシは、ホスティングプロバイダーに属するIPアドレスです。これらはAS(大規模データセンターの自律システム)の所属により識別できます。
利点:
- 高速で安定
- 低コスト
- 大規模なIPプール
欠点:
- 簡単に検出可能
- ブラックリストに登録されることが多い
- 厳格な保護を持つサイトには不適切
適用対象: SEOツール、可用性確認、厳格な保護のないAPIとの連携、テスト。
住宅用プロキシ
住宅用プロキシは、パートナープログラムまたはアプリケーション内のSDKを通じて提供される実際のユーザーのIPアドレスです。これらは通常のインターネットプロバイダー(ISP)に属しています。
利点:
- 通常のユーザーのように見える
- 低いfraud score
- 広い地理的カバレッジ
- 検出が難しい
欠点:
- より高いコスト(トラフィック課金)
- 速度はエンドユーザーに依存
- IP「消失」の可能性(ユーザーがデバイスをオフにした)
適用対象: 保護されたサイトのスクレイピング、ソーシャルメディアとの連携、e-commerce、検出を避けることが重要なあらゆるタスク。
モバイルプロキシ
モバイルプロキシは、モバイルオペレーター(MTS、Beeline、Megafonなど)のIPアドレスです。CGNAT技術により特別なステータスを持ちます。
利点:
- サイトからの最大の信頼
- 1つのIPを数千の実際のユーザーが使用 — バンが難しい
- アカウント作業に理想的
- リクエスト時のIP変更(ネットワーク再接続)
欠点:
- 最も高いコスト
- 限定的な速度
- 地理的選択肢が少ない
適用対象: マルチアカウンティング、Instagram/Facebook/TikTokとの連携、アカウント登録、バンのリスクが高いあらゆるタスク。
比較表
| パラメータ | データセンタ | 住宅用 | モバイル |
|---|---|---|---|
| 検出可能性 | 高い | 低い | 非常に低い |
| 速度 | 高い | 中程度 | 低~中程度 |
| コスト | $ | $$ | $$$ |
| ソーシャルメディア向け | 不適切 | 適切 | 理想的 |
| スクレイピング向け | シンプルなサイト | あらゆるサイト | 過剰 |
保護回避の高度なテクニック
基本的な方法が機能しない場合は、より複雑なテクニックを使用する必要があります。保護回避のいくつかの高度なアプローチを考えてみましょう。
Cloudflareおよび同様の保護の処理
Cloudflare、Akamai、PerimeterX — これらのシステムはブラウザを確認するためにJavaScriptチャレンジを使用します。単純なHTTPリクエストは通過しません。解決策のオプション:
1. 実際のブラウザを使用:
from playwright.sync_api import sync_playwright
def bypass_cloudflare(url, proxy):
with sync_playwright() as p:
browser = p.chromium.launch(
headless=False, # ときどきheadlessが検出される
proxy={"server": proxy}
)
page = browser.new_page()
page.goto(url)
# チェック通過を待つ(通常5~10秒)
page.wait_for_timeout(10000)
# チェックを通過したか確認
if "challenge" not in page.url:
# 後続のリクエスト用にCookieを保存
cookies = page.context.cookies()
return cookies
browser.close()
return None
2. 既製のソリューションを使用:
# cloudscraper — Cloudflare回避ライブラリ
import cloudscraper
scraper = cloudscraper.create_scraper(
browser={
'browser': 'chrome',
'platform': 'windows',
'desktop': True
}
)
scraper.proxies = {"http": proxy, "https": proxy}
response = scraper.get("https://protected-site.com")
CAPTCHAの解決
サイトがCAPTCHAを表示する場合、いくつかのアプローチがあります:
認識サービス: 2Captcha、Anti-Captcha、CapMonster。これらはあなたのためにCAPTCHAを解決します