免费图库API全攻略:Unsplash、Pexels、Wikimedia接入实测

目录

📌 配图是内容的第二张脸。三个免费图库 API,让你的文章从素颜到美颜只需要几行代码。


引言

你有没有经历过这种场景——文章写完了,盯着空白的配图位发呆,打开百度搜图,全是水印叠水印的"转载链",翻了三页也找不到一张能放心用的。

或者更惨:文章发出去三个月,收到一封版权索赔邮件。

说到底,找图不是艺术问题,是工程问题。既然我们有 API 能自动生成摘要、翻译文本、生成封面——为什么不能自动配图?

这篇文章,我实际注册并测试了市面上三个最主流的免费图库 API:UnsplashPexelsWikimedia Commons。它们各有千秋,从零门槛到无限制,总有一个适合你的工作流。


一、为什么要用图库 API?

用 API 接入图库,和手动下载图片,是完全不同的两件事:

维度手动下载API 接入
效率每篇搜索→浏览→下载→上传,5-10 分钟一行代码搞定,毫秒级
一致性风格杂乱可通过参数统一筛选
版权安全靠自觉,容易踩雷API 返回的图自带授权信息
自动化✅ 可嵌入 CI/CD、CMS 插件、写作工具链
批量处理不可能轻松取几十张按需筛选

如果你的内容创作流程是:定选题 → 写正文 → 找配图 → 发布,那么配图环节就是最应该被自动化的那个。毕竟,你不会每次发布都手写 HTML 对吧。


二、Unsplash API 接入 🆓

主页: unsplash.com/developers
文档: unsplash.com/documentation

2.1 一句话概括

Unsplash 是世界上最大的免费高清摄影社区,850 万+ 图片,42 万+ 摄影师。它的 API 是三者里审美最强、文档最完善的。

2.2 注册 & 获取密钥

  1. 访问 unsplash.com/oauth/applications 注册成为开发者
  2. 创建应用 → 同意 API 条款 → 获取 Access Key
  3. 初始为 Demo 模式,限额 50 req/h(足够个人博客使用)
  4. 如果有更高需求,可申请 Production 模式,限额提升至 5000 req/h

💰 价格标签:🆓 有免费层(Demo 50 req/h / Production 5000 req/h)

2.3 认证方式

Unsplash 支持两种认证:

公开认证(推荐,无需用户登录):

1
headers = {"Authorization": "Client-ID YOUR_ACCESS_KEY"}

OAuth2 用户认证(需要登录,用于点赞/收藏等用户操作):

1
2
3
4
5
6
7
8
9
# 获取 bearer token
response = requests.post("https://unsplash.com/oauth/token", data={
    "client_id": ACCESS_KEY,
    "client_secret": SECRET_KEY,
    "redirect_uri": REDIRECT_URI,
    "code": AUTH_CODE,
    "grant_type": "authorization_code"
})
token = response.json()["access_token"]

大多数场景下,用 Client-ID 就够了,无需折腾 OAuth。

2.4 Python 示例:关键词搜索图片

 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
import requests

ACCESS_KEY = "你的Access_Key"
BASE_URL = "https://api.unsplash.com"

def search_photos(query, per_page=10):
    """搜索 Unsplash 图片"""
    url = f"{BASE_URL}/search/photos"
    headers = {"Authorization": f"Client-ID {ACCESS_KEY}"}
    params = {
        "query": query,
        "per_page": per_page,
        "orientation": "landscape"  # landscape | portrait | squarish
    }
    
    resp = requests.get(url, headers=headers, params=params)
    data = resp.json()
    
    for photo in data["results"]:
        print(f"📷 {photo['alt_description']}")
        print(f"  作者: {photo['user']['name']} (@{photo['user']['username']})")
        print(f"  原图: {photo['urls']['raw']}")
        print(f"  下载: {photo['links']['download']}")
        print(f"  尺寸: {photo['width']}×{photo['height']}")
        print()
    
    return data["results"]

# 搜索"山水"
photos = search_photos("mountain landscape", per_page=5)

2.5 JavaScript 示例

 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
const ACCESS_KEY = "你的Access_Key";

async function searchPhotos(query, perPage = 10) {
  const url = new URL("https://api.unsplash.com/search/photos");
  url.searchParams.set("query", query);
  url.searchParams.set("per_page", perPage);
  url.searchParams.set("orientation", "landscape");

  const resp = await fetch(url, {
    headers: { Authorization: `Client-ID ${ACCESS_KEY}` }
  });
  const data = await resp.json();

  return data.results.map(photo => ({
    id: photo.id,
    description: photo.alt_description,
    author: photo.user.name,
    authorUrl: photo.user.links.html,
    rawUrl: photo.urls.raw,
    downloadUrl: photo.links.download,
    width: photo.width,
    height: photo.height
  }));
}

// 使用
searchPhotos("city skyline").then(console.log);

2.6 彩蛋:动态图片裁剪

Unsplash 图片 URL 支持实时裁剪和压缩,无需额外 API 调用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 原图
https://images.unsplash.com/photo-1506744038136-46273834b3fb

# 裁剪为 800×600
https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=800&h=600&fit=crop

# WebP 格式自动选择
https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=800&fm=webp

# 降低质量以加快加载
https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=800&q=75

底层用的是 Imgix,支持几十种变换参数。而且图片请求不计入 API 限额——只有 JSON 接口请求才计入。

2.7 限流监控

每个 API 请求的响应头都包含限流信息:

1
2
3
4
5
resp = requests.get("https://api.unsplash.com/search/photos?query=test", 
                     headers={"Authorization": f"Client-ID {ACCESS_KEY}"})

print(f"限额: {resp.headers['X-Ratelimit-Limit']}")
print(f"剩余: {resp.headers['X-Ratelimit-Remaining']}")

三、Pexels API 接入 🆓

主页: pexels.com/api
文档: pexels.com/api/documentation

3.1 一句话概括

Pexels 提供高质量照片和视频素材,商业最友好:授权极其宽松,使用限制最少。

3.2 注册 & 获取密钥

  1. 访问 pexels.com/api → 点击"获取 API 密钥"
  2. 注册/登录 Pexels 账号 → 填写应用信息
  3. 即刻获取 API Key,无需审核等待

💰 价格标签:🆓 有免费层(200 req/h / 20,000 req/月)

3.3 认证方式

Pexels 认证非常简单,只需在请求头加上你的 API Key:

1
headers = {"Authorization": "YOUR_API_KEY"}

没有 OAuth、没有 Client ID / Secret 之分,一把钥匙走天下。注册即用,零等待。

3.4 Python 示例:搜索照片

 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
import requests

API_KEY = "你的API_Key"
BASE_URL = "https://api.pexels.com/v1"

def search_photos(query, per_page=15):
    """搜索 Pexels 图片"""
    url = f"{BASE_URL}/search"
    headers = {"Authorization": API_KEY}
    params = {
        "query": query,
        "per_page": per_page,
        "orientation": "landscape",  # landscape | portrait | square
        "size": "large",              # large(24MP) | medium(12MP) | small(4MP)
        "locale": "zh-CN"             # 中文搜索结果
    }

    resp = requests.get(url, headers=headers, params=params)
    data = resp.json()

    for photo in data["photos"]:
        print(f"📷 摄影: {photo['photographer']}")
        print(f"   原图: {photo['src']['original']}")
        print(f"   大图: {photo['src']['large2x']}")
        print(f"   横图: {photo['src']['landscape']}")
        print(f"   主色: {photo['avg_color']}")
        print(f"   尺寸: {photo['width']}×{photo['height']}")
        print()

    return data["photos"]

photos = search_photos("城市夜景", per_page=5)

3.5 搜视频

Pexels 的一大独家优势是也提供免费视频

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def search_videos(query, per_page=10):
    """搜索 Pexels 视频"""
    url = f"{BASE_URL}/videos/search"
    headers = {"Authorization": API_KEY}
    params = {
        "query": query,
        "per_page": per_page,
        "size": "large",       # large(4K) | medium(Full HD) | small(HD)
        "locale": "zh-CN"
    }

    resp = requests.get(url, headers=headers, params=params)
    data = resp.json()

    for video in data["videos"]:
        print(f"🎬 {video['url']}")
        print(f"   时长: {video['duration']}s")
        # 获取最高清的视频文件
        best = max(video["video_files"], key=lambda f: f.get("width", 0) * f.get("height", 0))
        print(f"   画质: {best['width']}×{best['height']}")
        print(f"   链接: {best['link']}")
        print()
    
    return data["videos"]

3.6 JavaScript 示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const API_KEY = "你的API_Key";

async function searchPexels(query, perPage = 15) {
  const url = new URL("https://api.pexels.com/v1/search");
  url.searchParams.set("query", query);
  url.searchParams.set("per_page", perPage);
  url.searchParams.set("orientation", "landscape");

  const resp = await fetch(url, {
    headers: { Authorization: API_KEY }
  });
  const data = await resp.json();

  return data.photos.map(p => ({
    id: p.id,
    photographer: p.photographer,
    url: p.src.original,
    large: p.src.large2x,
    avgColor: p.avg_color,
    width: p.width,
    height: p.height
  }));
}

四、Wikimedia Commons API 接入 💰免费

主页: commons.wikimedia.org
API 端点: https://commons.wikimedia.org/w/api.php
文档: mediawiki.org/wiki/API:Main_page

4.1 一句话概括

Wikimedia Commons 是维基百科的媒体库,拥有 1 亿+ 免费媒体文件,完全免费,无需注册,无 API 密钥,无速率限制。

但——它没有专门为"找图"设计的 RESTful API。你得用 MediaWiki Action API 来搜索和查询。

4.2 不需要密钥

对,你没看错。直接发请求就行:

1
2
3
4
import requests

# 不需要任何认证
url = "https://commons.wikimedia.org/w/api.php"

官方建议添加 User-Agent 标识你的应用,这不是限制,是礼仪:

1
2
3
headers = {
    "User-Agent": "MyApp/1.0 (https://myapp.com; [email protected])"
}

💰 价格标签:💰 完全免费(无限次调用,无速率限制)

4.3 搜索图片

使用 action=query&list=search 在文件命名空间(ns=6)搜索:

 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
import requests

def search_commons_images(query, limit=20):
    """搜索 Wikimedia Commons 图片"""
    url = "https://commons.wikimedia.org/w/api.php"
    params = {
        "action": "query",
        "list": "search",
        "srsearch": query,
        "srnamespace": 6,           # File 命名空间
        "srlimit": limit,
        "srprop": "size|wordcount|timestamp",
        "format": "json"
    }
    headers = {
        "User-Agent": "ContentTool/1.0 ([email protected])"
    }

    resp = requests.get(url, params=params, headers=headers)
    data = resp.json()

    titles = [item["title"] for item in data["query"]["search"]]
    return titles

# 搜索
titles = search_commons_images("Great Wall of China", limit=10)
print(titles)
# ['File:The Great Wall of China at Jinshanling.jpg', ...]

4.4 获取图片 URL 和版权信息

拿到文件名后,需要再请求一次来获取图片 URL:

 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
55
def get_image_info(file_titles):
    """获取图片的 URL 和详细信息"""
    url = "https://commons.wikimedia.org/w/api.php"
    params = {
        "action": "query",
        "titles": "|".join(file_titles),
        "prop": "imageinfo",
        "iiprop": "url|size|extmetadata|user|timestamp|mime",
        "format": "json"
    }
    headers = {"User-Agent": "ContentTool/1.0 ([email protected])"}

    resp = requests.get(url, params=params, headers=headers)
    data = resp.json()

    results = []
    for page_id, page in data["query"]["pages"].items():
        if "imageinfo" not in page:
            continue
        info = page["imageinfo"][0]
        meta = info.get("extmetadata", {})

        # 提取版权信息
        license_name = meta.get("LicenseShortName", {}).get("value", "未知")
        license_url = meta.get("LicenseUrl", {}).get("value", "")
        attribution = meta.get("Attribution", {}).get("value", "")
        artist = meta.get("Artist", {}).get("value", "")

        results.append({
            "title": page["title"],
            "url": info["url"],
            "width": info["width"],
            "height": info["height"],
            "size_bytes": info["size"],
            "mime": info["mime"],
            "license": license_name,
            "license_url": license_url,
            "attribution": attribution,
            "artist": artist,
            "user": info.get("user", "")
        })

    return results

# 组合使用
titles = search_commons_images("sakura japan", limit=10)
images = get_image_info(titles)

for img in images:
    print(f"📷 {img['title']}")
    print(f"   图片: {img['url']}")
    print(f"   尺寸: {img['width']}×{img['height']}")
    print(f"   授权: {img['license']}{img['license_url']}")
    print(f"   署名: {img['attribution'] or img['artist']}")
    print()

4.5 一步到位:搜索 + 图片信息

generator=search 可以把两步合成一步:

 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
def search_with_images(query, limit=10):
    """一步完成搜索+获取图片信息"""
    url = "https://commons.wikimedia.org/w/api.php"
    params = {
        "action": "query",
        "generator": "search",
        "gsrsearch": query,
        "gsrnamespace": 6,
        "gsrlimit": limit,
        "prop": "imageinfo",
        "iiprop": "url|size|extmetadata|user",
        "format": "json"
    }
    headers = {"User-Agent": "ContentTool/1.0 ([email protected])"}

    resp = requests.get(url, params=params, headers=headers)
    data = resp.json()

    results = []
    for page_id, page in data.get("query", {}).get("pages", {}).items():
        if "imageinfo" not in page:
            continue
        info = page["imageinfo"][0]
        meta = info.get("extmetadata", {})
        results.append({
            "title": page["title"],
            "url": info["url"],
            "license": meta.get("LicenseShortName", {}).get("value", "CC BY-SA"),
            "attribution": meta.get("Attribution", {}).get("value", "")
        })
    return results

images = search_with_images("Eiffel Tower sunset")

五、三座大山对比

维度UnsplashPexelsWikimedia Commons
免费额度50 req/h (Demo) / 5000 req/h (Production)200 req/h / 20,000 req/月🎉 无限
注册难度注册 → 创建应用 → 同意条款注册 → 即时获取 Key🎉 无需注册
审美水平⭐⭐⭐⭐⭐ 摄影作品级⭐⭐⭐⭐ 高质量素材⭐⭐⭐ 良莠不齐,参差大
图片数量850万+300万+1亿+
视频支持❌ 仅图片✅ 照片 + 视频✅ 照片 + 视频 + 音频
中文搜索一般(推荐英文关键词)✅ 原生支持 locale=zh-CN⚠️ 支持但质量不如英文
授权宽严Unsplash License(可商用,署名非强制但建议)Pexels License(可商用,署名非强制)逐张不同!CC0 / CC BY / CC BY-SA 都有
API 设计RESTful,设计最优雅RESTful,设计简洁MediaWiki API,学习曲线较陡
动态裁剪✅ Imgix(不计入 API 限额)❌ 固定尺寸预设❌ 需自行处理
SDKJS / PHP / Ruby / iOS / Android社区 Python / JS 封装Pywikibot / mwclient
适用场景博客插图 / 设计素材 / 高质量配图商业项目 / 中英文配图 / 视频背景历史/文化/科普文章 / 学术 / 无限制批量爬取

六、批量配图最佳实践

实际项目中,你不会每次手动写代码搜索。一个成熟的批量配图流水线长这样:

 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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import hashlib
import os
import time
import requests

class ImageBatcher:
    """批量图片获取 + 本地缓存"""
    
    def __init__(self, cache_dir="./image_cache"):
        self.cache_dir = cache_dir
        os.makedirs(cache_dir, exist_ok=True)
    
    def _cache_key(self, url):
        return hashlib.md5(url.encode()).hexdigest()
    
    def batch_search(self, api_func, keywords, per_keyword=5, 
                     min_ratio=1.3, max_ratio=2.5):
        """
        批量搜索 + 宽高比筛选
        
        Args:
            api_func: 搜索函数,返回图片列表
            keywords: 关键词列表,如 ["mountain", "city", "ocean"]
            per_keyword: 每个关键词取几张
            min_ratio/max_ratio: 宽高比范围(1.3-2.5 适合文章横幅)
        """
        results = {}
        
        for kw in keywords:
            try:
                photos = api_func(kw, per_page=per_keyword * 2)
                filtered = []
                
                for p in photos:
                    ratio = p["width"] / p["height"]
                    if min_ratio <= ratio <= max_ratio:
                        filtered.append(p)
                        if len(filtered) >= per_keyword:
                            break
                
                results[kw] = filtered
                print(f"✅ {kw}: 找到 {len(filtered)} 张合适图片")
                time.sleep(1)  # 礼貌间隔
                
            except Exception as e:
                print(f"❌ {kw}: {e}")
        
        return results
    
    def download_and_cache(self, photo_url, download_url=None):
        """
        下载并缓存图片到本地
        
        Unsplash 要求记录下载事件(通过 download_location 端点),
        这里一并处理。
        """
        cache_path = os.path.join(self.cache_dir, 
                                   f"{self._cache_key(photo_url)}.jpg")
        
        if os.path.exists(cache_path):
            return cache_path  # 命中缓存
        
        # Unsplash: 需要先触发 download 事件(合规)
        if download_url:
            requests.get(download_url)
        
        resp = requests.get(photo_url, stream=True)
        with open(cache_path, "wb") as f:
            for chunk in resp.iter_content(8192):
                f.write(chunk)
        
        return cache_path


# 使用示例
batcher = ImageBatcher()

keywords = ["mountain sunrise", "office workspace", "ocean waves"]
photos = batcher.batch_search(search_unsplash, keywords, per_keyword=3)

for kw, p_list in photos.items():
    for p in p_list:
        path = batcher.download_and_cache(p["url"], p.get("download_url"))
        print(f"  💾 {kw}{path}")

最佳实践清单

  1. 关键词用英文:三个图库的内容都以英文为主,用英文关键词命中率高得多
  2. 宽高比筛选:横幅/封面用 16:9(≈1.78),正方形配图用 1:1
  3. 本地缓存:同一张图不要反复下载,用 URL hash 做缓存 key
  4. 记录下载事件:Unsplash 要求通过 download_location 端点触发下载计数(对摄影师友善)
  5. 做限流保护:即使无限制的 Wikimedia Commons 也别疯狂并发,做个 1s 间隔
  6. 信用作者信息:下载时一并保存作者名和授权,发布时自动嵌入署名

七、授权避坑指南

免费 ≠ 可以随便用。三个图库的授权差异很大,这块最容易踩坑。

7.1 Unsplash License

  • ✅ 可商用(网站、App、广告、印刷品)
  • ✅ 可修改(裁剪、调色、加文字)
  • ✅ 署名非强制,但强烈建议,尤其是用到摄影师肖像作品时
  • 不能原封不动转售照片(如把图传上另一个图库)
  • 不能暗示照片里的人物或品牌为你的产品背书
  • 不能将照片用作商标(logo)的一部分

7.2 Pexels License

  • ✅ 可商用,自由度与 Unsplash 相当
  • ✅ 署名非强制
  • ✅ 可修改、编辑
  • ❌ 不能未经修改就转售(比如做成海报卖)
  • ❌ 可识别人物不能以负面、冒犯方式使用
  • 不能在其他素材图库或壁纸平台重新分发

📌 Pexels 与 Unsplash 在 2022 年已被 Canva 收购,但两个品牌和授权体系仍独立运行。

7.3 Wikimedia Commons 授权:最复杂,务必逐张检查

这是最关键的一段。Wikimedia Commons 上每张图片的授权都不一样

许可证可商用需署名可修改禁止
CC0 / Public Domain
CC BY 2.0/4.0✅ 必须署名
CC BY-SA 2.0/4.0✅ 必须署名衍生作品须用相同许可
CC BY-NC❌ 不可商用商业用途
CC BY-ND❌ 不可修改修改作品
GNU GPL / FAL需仔细阅读条款

检查授权的方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
def check_license(image_info):
    """判断图片是否可以安全商用"""
    license_name = image_info.get("license", "")
    
    friendly_licenses = ["CC0", "Public domain", "CC BY 2.0", 
                         "CC BY 3.0", "CC BY 4.0", "CC BY-SA 2.0",
                         "CC BY-SA 3.0", "CC BY-SA 4.0"]
    
    restricted = ["CC BY-NC", "CC BY-ND", "CC BY-NC-SA", 
                  "CC BY-NC-ND", "All rights reserved"]
    
    if any(l.lower() in license_name.lower() for l in restricted):
        return "⚠️ 限制使用"
    
    if any(l.lower() in license_name.lower() for l in friendly_licenses):
        if "BY" in license_name:
            attribution = image_info.get("attribution", "未知作者")
            return f"✅ 可商用,署名: {attribution}"
        return "✅ 可自由使用(CC0/公有领域)"
    
    return f"❓ 请手动检查: {license_name}"

一句话总结: Unsplash 和 Pexels 闭着眼睛用,Wikimedia Commons 睁大眼睛检查。


总结

你的需求推荐选择理由
博客配图,追求美感Unsplash摄影质量天花板,动态裁剪
商业项目,中英文都搜Pexels授权清晰,中文搜索友好,有视频
历史/科学/文化深度文章Wikimedia Commons独家内容,完全免费无限制
自动化批量配图Unsplash + 本地缓存API 设计最优雅,动态裁剪省流量
零门槛快速开始Pexels注册即用,一把 Key 走天下

三个 API 搭配使用,效果最佳:Unsplash 做主图,Pexels 做副图和视频,Wikimedia Commons 填补特定领域的深度需求


参考来源

  1. Unsplash API 官方文档 — 一手来源,API 授权、限流、接口定义
  2. Unsplash API 开发者门户 — 官方申请入口,最新 API 状态
  3. Pexels API 官方文档 — 一手来源,接口、限流、授权说明
  4. Pexels License 条款 — 官方授权说明,可商用/署名规则
  5. Wikimedia Commons API 文档 — 官方 API 说明,MediaWiki Action API
  6. MediaWiki API 官方文档 — Wikimedia 技术文档,search/allimages 等模块详解
  7. Unsplash License 条款 — 官方授权条款,商用限制说明
  8. 第三方 Pexels API 中文翻译文档 — 腾讯云开发者社区译稿,辅助参考

延伸阅读

原文链接: https://www.17you.com/freeresources/free-image-api-guide/ 已复制!
寻找合作和资源

如果你也对文章内容或者分享的资源和机会有兴趣,欢迎联系我。

请点击联系我


相关内容

发现新版本

当前站点有新版本可用。