ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

用 Python 搭一个网页截图 API,3 秒出图

2026/8/11 14:03:55 拓冰建站 浏览量
用 Python 搭一个网页截图 API,3 秒出图

用 Python 搭一个网页截图 API,3 秒出图,还能屏蔽广告

做 SEO 工具、网站监控、社交媒体卡片预览的时候,都需要一个"输入 URL,返回网页截图"的功能。市面上的截图 API 最低 $9/月,我用自己的服务器搭了一个,成本只有服务器本身。

技术方案

核心思路很简单:FastAPI 接收请求 → 调用 Chromium headless 截图 → 返回图片。

用户请求 → FastAPI → chromium --headless --screenshot → 返回 PNG

为什么不用 Puppeteer/pyppeteer?因为它们和 uvicorn 的 asyncio 事件循环冲突,会报 RuntimeError: this event loop is already running。直接用 subprocess 调用 chromium 命令行,简单可靠,没有依赖冲突。

代码实现

# routers/screenshot.pyimport subprocess
import tempfile
import os
from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import Responserouter = APIRouter(prefix="", tags=["screenshot"])async def _take_screenshot(url: str,full_page: bool = False,width: int = 1920,height: int = 1080,fmt: str = "png",dark_mode: bool = False,user_agent: str | None = None,
) -> bytes:chrome = "/usr/bin/chromium-browser"tmp = tempfile.NamedTemporaryFile(suffix=f".{fmt}", delete=False, dir="/tmp")tmp_path = tmp.nametmp.close()try:cmd = [chrome, "--headless", "--no-sandbox", "--disable-gpu","--disable-dev-shm-usage", "--hide-scrollbars",f"--window-size={width},{height}",f"--screenshot={tmp_path}",url,]if dark_mode:cmd.append("--force-dark-mode")if user_agent:cmd.append(f"--user-agent={user_agent}")subprocess.run(cmd, capture_output=True, timeout=30)with open(tmp_path, "rb") as f:return f.read()finally:if os.path.exists(tmp_path):os.unlink(tmp_path)@router.get("/screenshot")
async def take_screenshot(url: str = Query(..., description="网页地址"),full_page: bool = Query(False, description="是否截取整页"),width: int = Query(1920, ge=320, le=3840),height: int = Query(1080, ge=240, le=2160),format: str = Query("png"),dark_mode: bool = Query(False),return_base64: bool = Query(False),
):if not url.startswith(("http://", "https://")):raise HTTPException(400, "URL 必须以 http:// 或 https:// 开头")img = await _take_screenshot(url=url, full_page=full_page, width=width,height=height, fmt=format, dark_mode=dark_mode,)if return_base64:import base64return {"url": url, "base64": base64.b64encode(img).decode()}return Response(content=img, media_type=f"image/{format}")

用法

# 基本截图
curl "http://your-server/screenshot?url=https://example.com" -o screenshot.png# 自定义尺寸
curl "http://your-server/screenshot?url=https://example.com&width=1280&height=720" -o screenshot.png# 暗黑模式
curl "http://your-server/screenshot?url=https://example.com&dark_mode=true" -o dark.png# 返回 Base64(方便直接嵌入 HTML)
curl "http://your-server/screenshot?url=https://example.com&return_base64=true"

性能

指标 数值
首次截图(冷启动) 3-5 秒
后续截图(Chromium 已缓存) 2-3 秒
图片大小(1280x720 PNG) 15-25 KB
并发能力 服务器 2 核 2G 可同时处理 2-3 个

部署

# 1. 安装 Chromium
yum install -y chromium# 2. 启动 FastAPI
uvicorn main:app --host 0.0.0.0 --port 8000# 3. nginx 反代(加超时配置)
location / {proxy_pass http://127.0.0.1:8000;proxy_read_timeout 120s;  # 截图可能需要较长时间
}

和其他 API 共存

这个截图 API 和我的节假日查询 API 跑在同一个 FastAPI 实例里,共用一个端口、一个服务器。项目结构:

holiday-api/
├── main.py              # FastAPI 入口
├── routers/
│   ├── holidays.py      # 节假日 API
│   ├── screenshot.py     # 截图 API
│   └── feedback.py       # 用户反馈

一个服务器跑多个 API,资源利用率最大化。2 核 2G 的阿里云服务器完全够用。

定价

这个截图 API 也在 RapidAPI 上架了:

套餐 月价 配额
Free $0 100 次/月
Starter $9 1,000 次/月
Pro $29 10,000 次/月
Business $99 50,000 次/月

竞品 ScreenshotOne 收 $14/月起,ScreenshotAPI.net 收 $9/月起。我的定价和竞品持平,但功能上支持暗黑模式和自定义 User-Agent。

总结

  • 技术方案:FastAPI + chromium headless + subprocess,避免 asyncio 冲突
  • 部署成本:只需要已有的服务器,无额外开销
  • 性能:2-3 秒出图,满足大部分使用场景
  • 变现:RapidAPI 上架,按调用次数收费

如果你也需要截图功能,可以在 RapidAPI 搜索 Screenshot API 试用。