ネットワークリクエストの解析
検索エンジンの画像検索結果を効率的に取得するためには、ブラウザのデベロッパーツール(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のリトライ機能を組み込んだセッション管理を導入します。