サイトリニューアル案件では、旧サーバーから画像素材を回収する作業が発生することがあります。数が少なければ手動でも対応できますが、数十〜数百枚になると手作業では非効率です。
今回は、CSVファイルにまとめた画像URLからPythonで一括ダウンロードするスクリプトを紹介します。
必要なライブラリのインストール
まずは必要なライブラリをインストールします。
pip install requests pandas
CSVファイルの形式
CSVファイルは以下のような形式を想定しています。
filename,url
image001.jpg,https://example.com/images/sample1.jpg
image002.png,https://example.com/images/sample2.png
image003.jpg,https://example.com/images/sample3.jpg
画像一括ダウンロードスクリプト
import os
import requests
import pandas as pd
from urllib.parse import urlparse
import time
def download_images_from_csv(csv_file_path, download_folder='downloaded_images'):
"""
CSVファイルから画像URLを読み込み、一括ダウンロードする
Args:
csv_file_path (str): CSVファイルのパス
download_folder (str): ダウンロード先フォルダ
"""
# ダウンロードフォルダを作成
if not os.path.exists(download_folder):
os.makedirs(download_folder)
# CSVファイルを読み込み
try:
df = pd.read_csv(csv_file_path)
except Exception as e:
print(f"CSVファイルの読み込みに失敗しました: {e}")
return
# 必要な列があるかチェック
if 'url' not in df.columns:
print("CSVファイルに'url'列が見つかりません")
return
# ファイル名列がない場合はURLから自動生成
if 'filename' not in df.columns:
df['filename'] = df['url'].apply(lambda x: os.path.basename(urlparse(x).path))
success_count = 0
error_count = 0
print(f"画像ダウンロードを開始します({len(df)}件)")
for index, row in df.iterrows():
url = row['url']
filename = row['filename']
# ファイル名が空の場合はURLから取得
if pd.isna(filename) or filename == '':
filename = os.path.basename(urlparse(url).path)
# ファイル名に拡張子がない場合の処理
if '.' not in filename:
filename += '.jpg' # デフォルトでjpg拡張子を付与
file_path = os.path.join(download_folder, filename)
try:
# 画像をダウンロード
response = requests.get(url, timeout=30)
response.raise_for_status()
# ファイルに保存
with open(file_path, 'wb') as f:
f.write(response.content)
print(f"✓ {filename} をダウンロードしました")
success_count += 1
except requests.exceptions.RequestException as e:
print(f"✗ {filename} のダウンロードに失敗しました: {e}")
error_count += 1
except Exception as e:
print(f"✗ {filename} の保存に失敗しました: {e}")
error_count += 1
# サーバーに負荷をかけないよう少し待機
time.sleep(0.5)
print(f"\n処理完了: 成功 {success_count}件 / 失敗 {error_count}件")
# 使用例
if __name__ == "__main__":
# CSVファイルから画像をダウンロード
download_images_from_csv('image_urls.csv', 'images')
より高機能なバージョン
エラーハンドリングや進捗表示を強化したバージョンです。
import os
import requests
import pandas as pd
from urllib.parse import urlparse
import time
from datetime import datetime
def advanced_download_images(csv_file_path, download_folder='downloaded_images', max_retries=3):
"""
CSVファイルから画像を一括ダウンロード(高機能版)
Args:
csv_file_path (str): CSVファイルのパス
download_folder (str): ダウンロード先フォルダ
max_retries (int): 最大リトライ回数
"""
# ダウンロードフォルダを作成
if not os.path.exists(download_folder):
os.makedirs(download_folder)
# ログファイル用のタイムスタンプ
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
log_file = f"download_log_{timestamp}.txt"
# CSVファイルを読み込み
try:
df = pd.read_csv(csv_file_path)
except Exception as e:
print(f"CSVファイルの読み込みに失敗しました: {e}")
return
if 'url' not in df.columns:
print("CSVファイルに'url'列が見つかりません")
return
if 'filename' not in df.columns:
df['filename'] = df['url'].apply(lambda x: os.path.basename(urlparse(x).path))
success_count = 0
error_count = 0
skip_count = 0
print(f"画像ダウンロードを開始します({len(df)}件)")
with open(log_file, 'w', encoding='utf-8') as log:
log.write(f"ダウンロードログ - {datetime.now()}\n\n")
for index, row in df.iterrows():
url = row['url']
filename = row['filename']
if pd.isna(filename) or filename == '':
filename = os.path.basename(urlparse(url).path)
if '.' not in filename:
filename += '.jpg'
file_path = os.path.join(download_folder, filename)
# すでにファイルが存在する場合はスキップ
if os.path.exists(file_path):
print(f"- {filename} はすでに存在するためスキップします")
log.write(f"SKIP: {filename} (already exists)\n")
skip_count += 1
continue
# リトライ機能付きダウンロード
downloaded = False
for attempt in range(max_retries):
try:
response = requests.get(url, timeout=30, headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
})
response.raise_for_status()
with open(file_path, 'wb') as f:
f.write(response.content)
print(f"✓ {filename} をダウンロードしました ({len(response.content)} bytes)")
log.write(f"SUCCESS: {filename} - {url}\n")
success_count += 1
downloaded = True
break
except Exception as e:
if attempt < max_retries - 1:
print(f"⚠ {filename} の再試行中... ({attempt + 1}/{max_retries})")
time.sleep(2)
else:
print(f"✗ {filename} のダウンロードに失敗しました: {e}")
log.write(f"ERROR: {filename} - {url} - {e}\n")
error_count += 1
if downloaded:
time.sleep(0.5) # サーバー負荷軽減
# 結果をログに記録
log.write(f"\n処理完了: 成功 {success_count}件 / スキップ {skip_count}件 / 失敗 {error_count}件\n")
print(f"\n処理完了: 成功 {success_count}件 / スキップ {skip_count}件 / 失敗 {error_count}件")
print(f"詳細ログ: {log_file}")
# 使用例
if __name__ == "__main__":
advanced_download_images('image_urls.csv', 'images', max_retries=3)
使用方法
スクリプトを使用する手順は以下の通りです。
1. CSVファイルの準備
「filename」と「url」の列を持つCSVファイルを用意します。filenameが空の場合はURLから自動で取得されます。
2. スクリプトの実行
Python環境でスクリプトを実行します。
python download_images.py
3. 結果の確認
指定したフォルダに画像ファイルがダウンロードされ、処理結果がコンソールに表示されます。
スクリプトの主な機能
- 自動フォルダ作成: ダウンロード先フォルダが存在しない場合は自動作成
- 重複チェック: 既にファイルが存在する場合はスキップ
- リトライ機能: ダウンロードに失敗した場合は指定回数まで再試行
- 進捗表示: 処理状況をリアルタイムで表示
- エラーログ: 成功・失敗の詳細をログファイルに記録
- サーバー負荷軽減: リクエスト間に適切な間隔を設定
まとめ
PythonとPandasを使用することで、CSVファイルに記載された画像URLから効率的に画像を一括ダウンロードできます。リトライ機能やログ出力機能を追加することで、大量の画像処理でも安定して動作するスクリプトを作成できます。
