Contents
1. Unsplash API の概要と登録手順
Unsplash の画像は高品質で商用利用も可能ですが、API 利用時には認証・クレジット表記・レートリミットを遵守する必要があります。このセクションでは、開発者アカウントの作成から基本的な利用規約までを順に解説します。
1‑1. 開発者アカウントの作成
Unsplash のデベロッパーポータル(https://unsplash.com/developers)で無料アカウントを取得します。
- 「Sign up」ボタンからメールアドレスまたは SNS で登録
- メール認証が完了すると、ダッシュボードへ遷移できるようになります
1‑2. アクセスキー(Access Key)の取得
API 呼び出しに必要なのは Public の Access Key だけです。Secret Key はサーバー側で保管し、決してフロントエンドに露出させません。
| 手順 | 内容 |
|---|---|
| 1 | ダッシュボードの New Application をクリック |
| 2 | アプリ名・説明・利用目的を入力し Create Application |
| 3 | 表示された Access Key と Secret Key を確認(Access Key が API 認証に使用) |
重要:Access Key は環境変数
UNSPLASH_ACCESS_KEYに保存し、コード上でハードコーディングしないことを徹底してください。
1‑3. 利用規約と必須クレジット表記
Unsplash の API を利用する際は、画像ごとに以下の形式でクレジットを表示する必要があります。
|
1 2 |
Photo by {photographer} on Unsplash |
photographer(撮影者名) と profile URL は検索結果 JSON の user.name と user.links.html に含まれています。
| 項目 | 内容 |
|---|---|
| クレジット表記 | 画像を表示する全ページ・アプリで必須。上記テンプレートに従うこと |
| 商用利用 | 無料プランでも商用プロダクトへの使用は OK。ただし大量ダウンロードや再配布は禁止 |
| API の利用目的 | Unsplash のサービス向上に資する用途であること(例:検索、表示、壁紙設定) |
1‑4. 最新のリクエスト上限(2026 年時点)
公式ドキュメントによると、Free プランは 5,000 リクエスト / 時間 が上限です。過去に「1 時間あたり 50 リクエスト」という情報が流布していましたが、2024 年の大型アップデートで緩和されました。
- 上限超過時は HTTP
429 Too Many Requestsが返ります - レスポンスヘッダー
X-Ratelimit-Limit,X‑Ratelimit-Remaining,Retry-Afterを活用すると、プログラム側で自動的に待機時間を算出できます
注記:有料プラン(Pro / Business)ではさらに高い上限が設定されます。最新の数値は必ず公式ページをご確認ください。
2. Python で API を呼び出す基本構成
Python の標準的な HTTP クライアント requests と、レートリミット制御に便利な ratelimit / backoff ライブラリを組み合わせると、堅牢かつ可読性の高い実装が可能です。
2‑1. 必要パッケージのインストール
|
1 2 |
pip install --upgrade requests ratelimit backoff |
requests:シンプルな HTTP クライアントratelimit:関数単位で呼び出し回数を制限backoff:指数バックオフ付きリトライ機構
2‑2. 認証ヘッダー付き GET ラッパー
以下の unsplash_get() は、認証ヘッダー自動付与と共通エラーハンドリングを行います。
関数は @ratelimit.sleep_and_retry デコレータで 5,000 リクエスト/時(≈1.39 リクエスト/秒)に制限しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import os import time import requests from ratelimit import limits, sleep_and_retry import backoff # 1 時間あたりの上限(公式上限:5,000) REQUESTS_PER_HOUR = 5_000 SECONDS_PER_REQUEST = 3600 / REQUESTS_PER_HOUR # ≈0.72 秒 UNSPLASH_ACCESS_KEY = os.getenv("UNSPLASH_ACCESS_KEY") if not UNSPLASH_ACCESS_KEY: raise RuntimeError("環境変数 UNSPLASH_ACCESS_KEY が設定されていません") @sleep_and_retry @limits(calls=REQUESTS_PER_HOUR, period=3600) def _raw_get(url: str, params: dict | None = None) -> requests.Response: """レートリミットを自動で守りつつ GET リクエストを実行する内部関数""" headers = { "Authorization": f"Client-ID {UNSPLASH_ACCESS_KEY}", "Accept-Version": "v1", } return requests.get(url, headers=headers, params=params, timeout=10) @backoff.on_exception( backoff.expo, (requests.exceptions.RequestException,), max_tries=4, jitter=backoff.full_jitter, ) def unsplash_get(endpoint: str, params: dict | None = None) -> dict: """ エラーハンドリングと指数バックオフ付きで API を呼び出す。 成功時は JSON データ(dict)を返す。失敗した場合は例外が送出される。 """ url = f"https://api.unsplash.com{endpoint}" response = _raw_get(url, params=params) # HTTP エラーは raise_for_status で捕捉 response.raise_for_status() return response.json() |
@limitsが呼び出し回数を制御、超過時は自動的に待機backoff.expoによりタイムアウトや一時的なネットワーク障害が起きても最大 4 回まで再試行(指数バックオフ)
3. 画像検索エンドポイントの利用方法
Unsplash の検索は /search/photos エンドポイントで実現します。このセクションではパラメータ解説と、取得結果から必要情報を抽出するサンプルコードを示します。
3‑1. /search/photos の主要パラメータ
| パラメータ | 説明 | デフォルト | 最大 |
|---|---|---|---|
query |
検索キーワード(必須) | — | 任意文字列 |
page |
ページ番号 | 1 | 任意(上限は API が返す total_pages) |
per_page |
1 ページあたりの件数 | 10 | 30 |
orientation |
画像向き (landscape, portrait, squarish) |
— | — |
使用例
|
1 2 3 4 5 6 7 8 9 10 11 12 |
def search_photos(keyword: str, page: int = 1, per_page: int = 15) -> dict: """ キーワード検索を実行し、JSON データを取得する。 """ params = { "query": keyword, "page": page, "per_page": per_page, "orientation": "landscape", } return unsplash_get("/search/photos", params=params) |
3‑2. 検索結果から画像 URL とクレジット情報を抽出
取得した JSON の構造は公式ドキュメントと同様です。regular サイズの URL が汎用的に使いやすいので、以下関数で一括抽出します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
from typing import List, TypedDict class ImageInfo(TypedDict): url: str photographer: str profile: str # 写真家の Unsplash プロフィール URL def extract_image_info(search_json: dict) -> List[ImageInfo]: """ `search_photos()` の戻り値から画像 URL とクレジット情報だけを抽出。 """ images: List[ImageInfo] = [] for item in search_json.get("results", []): images.append({ "url": item["urls"]["regular"], "photographer": item["user"]["name"], "profile": item["user"]["links"]["html"], }) return images |
4. ページネーションとレートリミット対策
大量の画像を取得したい場合は ページング と リクエスト数計算 が必須です。ここでは実装例と、ratelimit ライブラリによるスロットリング方法を紹介します。
4‑1. ページング実装例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
def fetch_all_images( keyword: str, max_pages: int = 3, per_page: int = 20, ) -> List[ImageInfo]: """ 複数ページに跨る検索結果を取得し、全画像情報のリストを返す。 各ページ間で 0.8 秒(公式上限 5,000/時)以上のスリープを入れる。 """ all_images: List[ImageInfo] = [] for page in range(1, max_pages + 1): json_data = search_photos(keyword, page=page, per_page=per_page) all_images.extend(extract_image_info(json_data)) # 必要に応じてバックオフを入れる time.sleep(max(SECONDS_PER_REQUEST, 0.8)) return all_images |
4‑2. リクエスト数の事前計算例
| キーワード | per_page |
取得したい総件数 | 必要ページ数 | 想定リクエスト数 |
|---|---|---|---|---|
| nature | 30 | 150 | 5 | 5 (検索) + 5 (画像ダウンロード) = 10 |
ポイント:検索リクエストはページ数分だけ、画像ダウンロードも同じだけ必要です。合計が上限
5,000を超えないように設計しましょう。
4‑3. ratelimit デコレータで自動スロットリング
検索関数やダウンロード関数に以下のデコレータを付与すれば、呼び出しごとに自動的に待機時間が挿入されます。
|
1 2 3 4 5 6 7 |
@sleep_and_retry @limits(calls=REQUESTS_PER_HOUR, period=3600) def download_image(url: str, dest_path: pathlib.Path) -> None: resp = requests.get(url, timeout=10) resp.raise_for_status() dest_path.write_bytes(resp.content) |
5. 画像のダウンロード・ローカル保存ベストプラクティス
実運用では、エラーハンドリング・リトライ・クレジット情報の永続化が重要です。以下は完成度の高いダウンロード関数例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import pathlib import backoff from typing import Mapping @backoff.on_exception(backoff.expo, (requests.exceptions.RequestException,), max_tries=3) def download_image(image: ImageInfo, dest_dir: pathlib.Path) -> pathlib.Path: """ 画像をダウンロードし、JPEG ファイルとクレジットテキストのペアで保存する。 戻り値は画像ファイルへの Path オブジェクト。 """ dest_dir.mkdir(parents=True, exist_ok=True) # URL の最後のパス要素が写真 ID になるのでそれをファイル名に使用 image_id = image["url"].split("/")[-1] img_path = dest_dir / f"{image_id}.jpg" txt_path = dest_dir / f"{image_id}.txt" # ダウンロード(リトライは backoff が担保) resp = requests.get(image["url"], timeout=10) resp.raise_for_status() img_path.write_bytes(resp.content) # クレジット情報を同名のテキストに保存 txt_path.write_text( f"Photo by {image['photographer']} on Unsplash\n{image['profile']}", encoding="utf-8", ) return img_path |
backoff.expoによる指数バックオフで一時的な失敗に自動リトライ- ダウンロード完了後は 同名
.txtへクレジットを書き込み、法的要件を満たす
6. 実用サンプル:ランダム壁紙取得ツール
以下は「起動時にキーワードからランダムに画像を取得し、デスクトップの壁紙として設定」する最小実装です。Python 標準ライブラリ + 前述のヘルパー関数だけで完結します。
6‑1. フロー概要
- キーワードリストからランダムに 1 件選択
fetch_all_images()(max_pages=1, per_page=30)で候補画像を取得- 取得した中からさらに 1 枚をランダム抽出
download_image()でローカル保存し、クレジットテキストも生成- OS に合わせた壁紙設定コマンドを実行
6‑2. 完全コード
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
import pathlib import random import platform import subprocess from typing import List # ── 設定値 ─────────────────────── KEYWORDS = ["nature", "cityscape", "technology", "abstract"] DEST_DIR = pathlib.Path("./wallpapers") MAX_PAGES = 1 PER_PAGE = 30 # ──────────────────────────────── def set_wallpaper(image_path: pathlib.Path) -> None: """OS に応じて壁紙を設定するユーティリティ""" system = platform.system() if system == "Darwin": # macOS script = f'''osascript -e 'tell application "System Events" to set picture of every desktop to "{image_path}"' ''' subprocess.run(script, shell=True, check=False) elif system == "Windows": # Windows import ctypes SPI_SETDESKWALLPAPER = 20 ctypes.windll.user32.SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, str(image_path), 3) else: # Linux (GNOME の例) subprocess.run( ["gsettings", "set", "org.gnome.desktop.background", "picture-uri", f"file://{image_path}"], check=False, ) def main() -> None: keyword = random.choice(KEYWORDS) print(f"🔍 キーワード: {keyword}") # ① 画像情報取得(検索 + ページング) candidates: List[ImageInfo] = fetch_all_images(keyword, max_pages=MAX_PAGES, per_page=PER_PAGE) if not candidates: print("⚠️ 画像が取得できませんでした。") return # ② ランダムに 1 枚選択 chosen = random.choice(candidates) # ③ ダウンロード & クレジット保存 img_path = download_image(chosen, DEST_DIR) print(f"✅ 保存先: {img_path}") # ④ 壁紙設定 set_wallpaper(img_path) print("🎉 壁紙を更新しました!") if __name__ == "__main__": main() |
ポイントまとめ
fetch_all_images()がレートリミットを自動的に考慮- 失敗時は
backoffによる最大 3 回リトライが働くため、安定稼働が期待できる - OS 別実装は最小限に抑えつつ、必要ならデスクトップ環境別のコマンドへ拡張可能
7. SDK の選択肢と比較(2026 年版)
7‑1. 現在提供されている公式・非公式 SDK
| 言語 | 公式 SDK 有無 | 主なパッケージ名 | メンテナンス状況 (2026/06) |
|---|---|---|---|
| Python | ❌(公式は未提供) | unsplash-py(サードパーティ) |
最終更新 2023 年、PR が少なく保守的 |
| JavaScript / TypeScript | ✅ | unsplash-js |
アクティブにメンテナンス中 |
| Ruby | ✅ | unsplash.rb |
定期リリースあり |
| Go | ✅ | unsplash-go |
2025 年に大幅改修 |
結論:Python 向けの公式 SDK は現在存在しません。安定性と柔軟性を求めるなら requests + ratelimit/backoff の組み合わせ が推奨です。サードパーティ SDK を使う場合は、メンテナンス状況・依存関係を必ず確認してください。
7‑2. unsplash-py と自前実装の比較
| 項目 | unsplash-py(非公式) |
自前実装 (requests + ライブラリ) |
|---|---|---|
| 導入コスト | 1 行でインスタンス生成可能 | requests は必須、追加でレートリミット用ライブラリが必要 |
| 機能網羅性 | 基本的な検索・取得のみ。最新エンドポイントの対応遅れあり | 任意エンドポイントに自由にアクセス可 |
| エラーハンドリング | 例外はシンプルだが再試行ロジックが無い | backoff による指数バックオフ、最大リトライ回数設定可能 |
| 学習効果 | 抽象化が高く内部実装が見えにくい | HTTP の基礎からレートリミットまで一通り学べる |
まとめ
- 開発者アカウントと Access Key を取得し、環境変数で安全に管理する
- 公式ドキュメント(2026/06 時点) では無料プランでも 5,000 リクエスト / 時間 が上限です。
X‑Ratelimit-*ヘッダーを活用して動的に待機させましょう - Python では
requests + ratelimit + backoffの組み合わせが最も汎用的かつ保守しやすい実装となります - クレジット表記は必須。取得した
user.nameとuser.links.htmlを利用して、画像ごとにテキストファイルで保存すると管理が楽です - ページング・リクエスト数計算を行い、上限超過しない設計(例:30 件 × 5 ページ = 150 件 → 合計 10 リクエスト)を徹底する
- 実務で使える ランダム壁紙取得ツール のサンプルコードは、OS 判定・リトライ・レートリミット制御がすべて組み込まれているので、そのままプロジェクトに取り込めます
このガイドをベースに、ぜひ自分だけの画像取得アプリやデザインツールを作成してみてください。質問や実装上の課題があれば、公式フォーラムや GitHub Discussions でコミュニティと情報交換することもおすすめです。 Happy coding!