Pythonによる画像検索エンジンのデータ収集とプロキシを活用した自動ダウンロード実装

ネットワークリクエストの解析

検索エンジンの画像検索結果を効率的に取得するためには、ブラウザのデベロッパーツール(F12)を使用して、画像データを配信しているAPIエンドポイントを特定する必要があります。「Network」タブを開き、ページをスクロールした際に発生する「acjson」などのリクエストを確認します。ここに含まれるクエリパラメータ(キーワード、ページ番号、1ページあたりの件数など)を模倣することで、プログラムから直接画像URLのリストを取得可能になります。

画像URLの抽出ロジック

特定のキーワードに基づき、画像検索APIから画像URLを収集する関数を実装します。ここではrequestsライブラリを使用してJSONレスポンスを取得し、必要な画像リンク(thumbURLなど)をリスト化します。

import requests

def fetch_baidu_image_urls(search_word, count=30):
    endpoint = "https://image.baidu.com/search/acjson"
    request_headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
    }
    
    query_params = {
        "tn": "resultjson_com",
        "ipn": "rj",
        "ct": "201326592",
        "fp": "result",
        "word": search_word,
        "queryWord": search_word,
        "cl": "2",
        "lm": "-1",
        "ie": "utf-8",
        "oe": "utf-8",
        "pn": "1",
        "rn": count,
    }
    
    try:
        response = requests.get(url=endpoint, params=query_params, headers=request_headers, timeout=10)
        response.encoding = "utf-8"
        response_data = response.json()
        
        links = []
        for item in response_data.get("data", []):
            if "thumbURL" in item:
                links.append(item["thumbURL"])
        return links
    except Exception as error:
        print(f"Error fetching URLs: {error}")
        return []

プロキシサーバーの導入

大量の画像を短時間にダウンロードすると、サーバーからアクセス制限を受ける可能性があります。これを回避するために、プロキシAPIを利用してリクエストごとにIPアドレスを変更する仕組みを構築します。

import time

def get_rotating_proxy(api_url):
    while True:
        try:
            resp = requests.get(api_url, timeout=5)
            proxy_addr = resp.text.strip()
            
            if "too many requests" in proxy_addr.lower():
                time.sleep(2)
                continue
            
            return {"https": f"http://{proxy_addr}"}
        except:
            time.sleep(1)
            continue

画像のローカル保存と一括処理

取得したURLリストをループ処理し、各画像をローカルディレクトリに保存します。ディレクトリが存在しない場合は自動で作成し、エラーが発生した場合はスキップして処理を継続するように設計します。

import os

def execute_image_download(url_list, save_dir, proxy_api=None):
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)
        
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
    }

    for index, image_url in enumerate(url_list):
        proxy_config = get_rotating_proxy(proxy_api) if proxy_api else None
        
        try:
            img_response = requests.get(
                url=image_url, 
                headers=headers, 
                proxies=proxy_config, 
                timeout=5
            )
            
            if img_response.status_code == 200:
                file_name = f"{index + 1}.jpg"
                file_path = os.path.join(save_dir, file_name)
                
                with open(file_path, "wb") as f:
                    f.write(img_response.content)
                print(f"Successfully saved: {file_name}")
            
        except Exception as e:
            print(f"Failed to download {image_url}: {e}")
            continue

if __name__ == "__main__":
    # 使用例
    keyword = "landscape"
    target_urls = fetch_baidu_image_urls(keyword, count=50)
    # プロキシAPIのURLがある場合は引数に渡す
    execute_image_download(target_urls, save_dir=keyword)

パフォーマンス最適化の指針

実運用において処理速度を向上させるためには、以下の手法が有効です。

  • タイムアウト設定: 応答の遅いプロキシやサーバーで処理が止まらないよう、timeout値を適切に設定します。
  • 並列処理: concurrent.futuresモジュールなどを用いてマルチスレッド化することで、ダウンロード速度を飛躍的に高めることが可能です。
  • リトライ処理: ネットワークの一時的な不安定さに対応するため、urllib3のリトライ機能を組み込んだセッション管理を導入します。

タグ: Python requests webscraping proxy JSON

9月20日 05:40 投稿