← ブログに戻る

CVデータセットのための画像パース: 必要なトラフィックと選ぶべきプロキシ

CVモデルの学習のために数千の画像を収集するのに実際にどれだけのトラフィックが必要か、どのプロキシを使用するか、ブロックされないパーサーの書き方について解説します。

📅2026年11月1日

コンピュータビジョンモデルのトレーニングのために数千の画像を収集することは、ほぼ常に2つの問題に直面します: データソース(Google Images、Pinterest、マーケットプレイス、ストックサイト)からのブロックと予想外に高いトラフィック消費です。1つのIPアドレスはすぐにバンされ、プロキシトラフィックの請求はデータセットのアノテーション自体のコストを超える可能性があります。この記事では、ブロックによってデータを失わない画像パーサーを設計する方法と、トラフィックの予算を事前に計算する方法を考察します。

CV用の画像収集におけるプロキシの必要性

コンピュータビジョン用のデータセットは、通常1つのソースから収集されることはありません。通常、画像検索結果、マーケットプレイスの商品カード、ストックフォト、ソーシャルメディア、オープンAPIの組み合わせです。これらのほとんどのソースは、1つのIPからのリクエスト数に制限を設けています: Google Imagesは数百の連続リクエストの後にキャプチャを表示し、Pinterestは一時的にAPIへのアクセスをブロックし、WildberriesやOzonは疑わしいアクティビティがあると空のカードを返したり、確認ページにリダイレクトします。

プロキシなしでは、1つのアドレスから1日に数百または数千の画像に制限されます。50,000〜500,000画像のデータセットが必要な場合(これは通常、分類や検出のタスクにおける畳み込みネットワークやトランスフォーマーに必要な数です)、分散したIPアドレスプールなしでは、合理的な時間内にそれを収集することは物理的に不可能です — それとも、常にブロックに直面するか、時間帯や地理的制限によって大きく偏ったサンプルを取得することになります。

もう1つの理由は、データの地理的多様性です。モデルが撮影地域に関係なくオブジェクトを同じように認識する必要がある場合(たとえば、異なる国の交通標識やローカルマーケットプレイスの商品)、パーサーは異なる国のIPに接続する必要があります。1つのデータセンターからの1つの出口IPでは、そのような多様性を提供できません。

データセットに実際に必要なトラフィック量

画像収集時のトラフィック消費はしばしば過小評価されます。問題は、画像自体のサイズだけでなく、HTMLページ、JSバンドル、プレビュー、トラッキングピクセル、CSSもプロキシを通じて流れることです。パーサーが必要なURLに正確に設定されていない場合です。

コンテンツタイプ 平均サイズ 10,000件あたりのトラフィック
プレビュー/サムネイル (150–300 px) 15–40 KB 約250 MB
中解像度の写真 (800–1200 px) 80–200 KB 約1.4 GB
高解像度の写真 (2000+ px) 400 KB – 1.5 MB 約9.5 GB
商品カードのHTMLページ (画像なし) 150–400 KB 約2.7 GB

実際には、もし中解像度の画像を100,000枚、商品カードのページとともに収集する場合(アノテーションの抽出のために — カテゴリー、ボックス、属性)、最終的なトラフィック消費は通常25〜45 GBの範囲に収まります。小さなオブジェクトの検出タスクのために高解像度の画像が必要な場合は、同じ100,000件で80〜150 GBを見込んでください。これらの数字は、事前にプロキシの料金プランを選ぶ際に考慮すべきです。

データセンター、住宅、モバイル: どれを選ぶべきか

画像収集において重要な3つのパラメータがあります: スピード、トラフィックコスト、ブロックに対する耐性。これらのパラメータは、異なるタイプのプロキシで大きく異なります。

パラメータ データセンター 住宅 モバイル
スピード 高い 中程度 低〜中程度
バンに対する耐性 低い 高い 非常に高い
トラフィックコスト 低い 中〜高 高い
適している用途 オープンAPI、厳しい保護のないストック Google Images、Pinterest、マーケットプレイス 厳しいアンチボット保護のあるソーシャルメディア

ほとんどの画像収集タスクにおいて最適なバランスを提供するのは、住宅プロキシです — IPは通常のユーザーのように見えるため、マーケットプレイスや画像検索エンジンのアンチボットシステムがキャプチャをトリガーすることが少なくなります。もしソースがオープンなストックフォトや厳しい制限のないAPIであれば、データセンタープロキシを使用する方が安価で、高速で大容量のトラフィックをより低いGB単価で流すことができます。モバイルアプリや高度なアンチボット保護のあるソーシャルメディアから画像を収集する場合は、モバイルプロキシが最適です — これらは通信事業者の実際のIPを使用し、ほとんどの場合ブロックされることはありません。

プロキシのローテーションを用いたrequestsによる基本的なパーサー

スタートには、各リクエストごとにプロキシをローテーションするシンプルな同期スクリプトが適しています。以下は、コンテンツタイプを確認し、ファイルサイズを制限して、誤って不適切なフォーマットの重いファイルをダウンロードしないようにするURLリストから画像をダウンロードする例です。

import requests
import itertools
import hashlib
import os

PROXIES = [
    "http://user:[email protected]:10000",
    "http://user:[email protected]:10000",
    "http://user:[email protected]:10000",
]
proxy_cycle = itertools.cycle(PROXIES)

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Accept": "image/avif,image/webp,image/*,*/*;q=0.8",
}

def download_image(url, save_dir="dataset", max_size_mb=10, timeout=15):
    proxy = next(proxy_cycle)
    proxies = {"http": proxy, "https": proxy}
    try:
        resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=timeout, stream=True)
        resp.raise_for_status()

        content_type = resp.headers.get("Content-Type", "")
        if "image" not in content_type:
            return None

        content_length = int(resp.headers.get("Content-Length", 0))
        if content_length > max_size_mb * 1024 * 1024:
            return None

        file_hash = hashlib.md5(url.encode()).hexdigest()
        ext = content_type.split("/")[-1].split(";")[0]
        filepath = os.path.join(save_dir, f"{file_hash}.{ext}")

        os.makedirs(save_dir, exist_ok=True)
        with open(filepath, "wb") as f:
            for chunk in resp.iter_content(chunk_size=8192):
                f.write(chunk)

        return filepath
    except requests.exceptions.RequestException as e:
        print(f"{url}を{proxy}経由で取得中にエラーが発生しました: {e}")
        return None

重要なポイントは、レスポンスボディをダウンロードする前にContent-Lengthを確認することです。これにより、トラフィックを節約し、過度に重いファイルを完全にダウンロードする前に除外できます。itertools.cycleを使用したプロキシのローテーションは、IP間で負荷を均等に分散し、特定のアドレスのバンのリスクを減らします。

aiohttpを用いた非同期収集

requestsによる同期スクリプトは数千の画像には適していますが、50,000ファイル以上のデータセットには非同期性が必要です — さもなければ収集に数日かかります。aiohttpとセマフォを使用して並列性を制限することは、プロキシプールを過負荷にすることなく、数万の同時タスクを処理するための実用的な方法です。

import asyncio
import aiohttp
import itertools

PROXIES = [
    "http://user:[email protected]:10000",
    "http://user:[email protected]:10000",
]
proxy_cycle = itertools.cycle(PROXIES)
sem = asyncio.Semaphore(50)  # 同時リクエストの制限

async def fetch_image(session, url, idx):
    proxy = next(proxy_cycle)
    async with sem:
        try:
            async with session.get(url, proxy=proxy, timeout=15) as resp:
                if resp.status != 200:
                    return
                content_type = resp.headers.get("Content-Type", "")
                if "image" not in content_type:
                    return
                data = await resp.read()
                with open(f"dataset/{idx}.jpg", "wb") as f:
                    f.write(data)
        except Exception as e:
            print(f"{url}でエラーが発生しました: {e}")

async def main(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_image(session, url, i) for i, url in enumerate(urls)]
        await asyncio.gather(*tasks)

# asyncio.run(main(url_list))

50の同時接続のセマフォは出発点です。住宅プロキシがエラー429やタイムアウトの増加なしに負荷に耐えられる場合は、100〜150まで徐々に増やすことができます。重要なのは、失敗したリクエストの割合を監視することです: 5〜7%を超える場合は、並列性を減らすべきであり、プロキシプールを無限に増やすべきではありません。

Scrapy + プロキシミドルウェアによる大規模収集

内蔵のキュー、リトライ、URLの重複排除を持つデータセットのプロダクション収集には、ScrapyとImagesPipelineを使用する方が便利です。これにより、自動的に画像をダウンロードし、PILを使用してその有効性を確認し、さまざまなサイズのプレビューを生成できます。

# settings.py
ITEM_PIPELINES = {
    'scrapy.pipelines.images.ImagesPipeline': 1,
}
IMAGES_STORE = 'dataset_images'
IMAGES_MIN_HEIGHT = 200
IMAGES_MIN_WIDTH = 200

DOWNLOADER_MIDDLEWARES = {
    'myproject.middlewares.ProxyRotationMiddleware': 350,
}

CONCURRENT_REQUESTS = 32
DOWNLOAD_DELAY = 0.5
RETRY_TIMES = 3
# middlewares.py
import random

class ProxyRotationMiddleware:
    PROXIES = [
        "http://user:[email protected]:10000",
        "http://user:[email protected]:10000",
        "http://user:[email protected]:10000",
    ]

    def process_request(self, request, spider):
        request.meta['proxy'] = random.choice(self.PROXIES)

IMAGES_MIN_HEIGHTとIMAGES_MIN_WIDTHのパラメータは、自動的に小さなアイコンやスプライトを除外し、データセットを汚染し、無駄にトラフィックを消費します。DOWNLOAD_DELAYを0.5秒に設定することで、1つのプロキシからのリクエスト頻度を減らし、Pinterestのような厳しいアンチフロード監視を行っているソースでのキャプチャの割合を減少させます。

トラフィック消費を減らす方法

プロキシを通じたトラフィックは通常、量に基づいて課金されるため、あらゆる最適化が直接的に予算を節約します。以下は実用的なテクニックです:

  • プレビューを要求し、オリジナルを要求しない — トレーニングに512〜1024 pxの解像度が十分な場合は、ほとんどのソースが別のURLやクエリパラメータで必要なサイズの画像を提供します。
  • ボディをダウンロードする前にContent-Lengthでフィルタリングする — HEADリクエストまたはストリーミングGETのヘッダーを読むことで、過度に重いファイルをダウンロードするためのトラフィックを消費せずに除外できます。
  • 関連リソースのダウンロードを無効にする — パーサーがヘッドレスブラウザを介して動作する場合: CSS、フォント、トラッキングスクリプトをブロックし、HTMLと必要な画像のみを残します。
  • リクエスト前にURLを重複排除する — 同じ商品カードの異なるページに同じ画像がある場合(たとえば、Wildberries)、再度ダウンロードする必要はありません。
  • 再実行時にローカルキャッシュを使用する — デバッグ中にパーサーを再実行する際に、各テストコードの実行時にプロキシを介してトラフィックを流さないようにします。

よくあるエラー、403とレート制限

大量の画像を収集する際、パーサーは必然的に403、429のレスポンスや確認ページへの一時的なリダイレクトに直面します。これらのコードを正しく処理することで、トラフィックとプロキシプールを節約できます。

コード/症状 原因 対処法
403 Forbidden IPがソースのブラックリストに載っている プロキシのローテーション、User-Agentの変更
429 Too Many Requests 1分あたりのリクエスト制限を超えた DOWNLOAD_DELAYを増やし、並列性を減らす
キャプチャへのリダイレクト 行動分析がボットを疑った 住宅/モバイルIPに切り替える
空のContent-Length チャンクレスポンスまたは画像の代わりにダミー ダウンロードしたバイトの実際のサイズを確認する

各プロキシの成功したリクエストの割合をログに記録することも重要です。特定のIPが他のIPよりも403を安定して多く返す場合は、そのIPを自動的にローテーションから外し、全体のブロック統計に影響を与える前に対処するべきです。

プロキシトラフィックの予算計算

収集を開始する前に、トラフィックの量を事前に見積もることが有益です。事後に計算するのではなく、シンプルな式を使います: 画像の数 × ファイルの平均サイズ × オーバーヘッド係数(HTML、ヘッダー、エラーによる再リクエスト — 通常1.3〜1.6)。

中解像度の画像(約150 KB)のデータセット200,000件の計算例: 200,000 × 150 KB = 30 GBの純粋な画像サイズ。HTMLページと一時的なブロックによる再リクエストを考慮に入れると(係数1.5)、最終的な消費は約45 GBになります。ソースの一部がアンチボット保護のためにモバイルIPを必要とする場合は、プロキシプールに別途考慮してください。モバイルIPのトラフィックは通常、住宅やデータセンターよりも高くつきます。

良いプラクティスは、1,000〜2,000画像のパイロットバッチを収集し、実際のトラフィック消費とエラー率を測定し、その後、計画しているデータセット全体に外挿することです。これは、特定のソースの特性を考慮に入れているため、理論的な計算よりも正確です。

結論

コンピュータビジョンモデルのトレーニングのための画像収集は、データエンジニアリングとネットワークインフラストラクチャの適切な管理の交差点にあるタスクです。パーサーの適切なアーキテクチャ(非同期性、Content-Lengthによるフィルタリング、URLの重複排除)はトラフィックを節約し、プロキシの賢明な選択は、必要なデータセット量を数日で収集できるか、数週間のブロックを受けるかを決定します。

データソースが高度なアンチボット保護を使用している場合 — 画像検索エンジン、マーケットプレイス、ソーシャルメディア — 住宅プロキシから始めるべきです: これらはバンに対する耐性とトラフィックコストの間で最良のバランスを提供します。オープンAPIや厳しい制限のないストックの場合は、データセンタープロキシで節約する意味がありますが、最も保護されたモバイルアプリの場合は、最終的で最も難しい収集部分のためにモバイルプロキシを接続するのが最適です。