YouTube 代理下载
POST/openapi/v1/youtube/proxy-download — 视频每 10 分钟消耗 4 积分。
传入 YouTube 链接,返回与单个帖子提取相同的结构,并为 1080p 及以下的每个档位附上代理链接。在云服务器、VPS、Serverless 函数上直接下载代理链接即可,无需维护住宅代理、cookies 或 PO token。
为什么服务器下载 YouTube 会返回 403 Forbidden
调 /extract/post 拿到 googlevideo.com 直链后,从服务器下载却报 HTTP Error 403: Forbidden。我们的实测结果:
- 机房 IP 被拒绝。 同一条直链,从家庭宽带下载正常(
206),从亚洲、欧洲多个地区的机房服务器下载返回403。直链并不绑定提取时的 IP,YouTube 看的是下载时的 IP。 - 部分链接只允许美国 IP 下载。 带
gcr=us参数的链接,美国以外的 IP 下载一律返回403。
所以只在提取环节想办法(换工具、配 cookies 或 PO token)解决不了问题:只要下载发生在机房 IP 上,照样返回 403。
工作原理
- 你把 YouTube 链接发给
POST /openapi/v1/youtube/proxy-download。 - 我们提取视频,返回常规的提取结果,并为 1080p 及以下的每个档位加上代理链接。
- 你下载代理链接。我们的下载网络从 YouTube 取回文件并流式转发给你,YouTube 看不到你服务器的 IP。
响应里的直链(video_url、audio_url、resource_url)全部保留:1080p 以上的档位只有直链;如果你的服务器能正常下载直链(比如在家庭宽带上),也可以继续用直链。
请求与响应
curl -X POST https://api.snapany.com/openapi/v1/youtube/proxy-download \
-H "Authorization: Bearer sk_snapany_xxx" \
-H "Accept-Language: zh" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'
支持 youtube.com 链接(普通视频、Shorts、直播回放,以及 m. 与 music. 子域)和 youtu.be 链接。其他链接——包括 youtube-nocookie.com 嵌入链接和跳转到 YouTube 的短链(如 t.co)——返回 HTTP 400、错误码 unsupported_site,不扣费。
响应示例(有删减,ID 与链接均为占位符):
{
"site": "youtube",
"title": "Scenic tour of the Karst mountains",
"medias": [
{
"media_type": "video",
"resource_url": "https://rr1---sn-example.googlevideo.com/videoplayback?itag=18&expire=1700000000&sig=EXAMPLE",
"resource_proxy_url": "https://proxy.example.com/proxy?payload=EXAMPLE_360P_RESOURCE",
"preview_url": "https://i.ytimg.com/vi/EXAMPLE0001/maxresdefault.jpg",
"duration": 754,
"variants": [
{
"quality": 2160,
"quality_label": "4K",
"fps": 30,
"video_url": "https://rr1---sn-example.googlevideo.com/videoplayback?itag=313&expire=1700000000&sig=EXAMPLE",
"video_ext": "webm",
"video_codec": "vp9",
"video_filesize": 687194112,
"audio_url": "https://rr1---sn-example.googlevideo.com/videoplayback?itag=251&expire=1700000000&sig=EXAMPLE",
"audio_ext": "weba",
"audio_codec": "opus",
"audio_filesize": 11354112
},
{
"quality": 1080,
"quality_label": "1080p",
"fps": 30,
"video_url": "https://rr1---sn-example.googlevideo.com/videoplayback?itag=137&expire=1700000000&sig=EXAMPLE",
"video_proxy_url": "https://proxy.example.com/proxy?payload=EXAMPLE_1080P_VIDEO",
"video_ext": "mp4",
"video_codec": "h264",
"video_filesize": 181403648,
"audio_url": "https://rr1---sn-example.googlevideo.com/videoplayback?itag=140&expire=1700000000&sig=EXAMPLE",
"audio_proxy_url": "https://proxy.example.com/proxy?payload=EXAMPLE_1080P_AUDIO",
"audio_ext": "m4a",
"audio_codec": "aac",
"audio_filesize": 12202891
},
{
"quality": 360,
"quality_label": "360p",
"fps": 30,
"video_url": "https://rr1---sn-example.googlevideo.com/videoplayback?itag=18&expire=1700000000&sig=EXAMPLE",
"video_proxy_url": "https://proxy.example.com/proxy?payload=EXAMPLE_360P_VIDEO",
"video_ext": "mp4",
"video_codec": "h264",
"video_filesize": 50847744
}
]
},
{
"media_type": "audio",
"resource_url": "https://rr1---sn-example.googlevideo.com/videoplayback?itag=140&expire=1700000000&sig=EXAMPLE",
"resource_proxy_url": "https://proxy.example.com/proxy?payload=EXAMPLE_AUDIO_RESOURCE",
"duration": 754,
"variants": [
{
"audio_url": "https://rr1---sn-example.googlevideo.com/videoplayback?itag=140&expire=1700000000&sig=EXAMPLE",
"audio_proxy_url": "https://proxy.example.com/proxy?payload=EXAMPLE_AUDIO_EN",
"audio_ext": "m4a",
"audio_codec": "aac",
"audio_filesize": 12202891,
"language_tag": "en",
"language_name": "English"
}
]
}
],
"id": "EXAMPLE0001",
"post_url": "https://www.youtube.com/watch?v=EXAMPLE0001",
"created_at": "2025-06-02T12:00:00.000Z",
"author": { "username": "@travelchannel", "display_name": "Travel Channel" }
}
在单个帖子提取的响应之外多出的字段:
| 字段 | 位置 | 何时出现 |
|---|---|---|
video_proxy_url | 档位(variant) | 该档位在 1080p 及以下 |
audio_proxy_url | 档位(variant) | 1080p 及以下且音频分离的视频档位;音频媒体的每个语言档位 |
resource_proxy_url | 视频 / 音频媒体 | resource_url 对应的文件在 1080p 及以下 |
超过 3 GB 的文件不带代理链接。响应里没有 preview_proxy_url,也没有过期时间字段——有效期规则见下文。
完整 schema 见 API 参考。
用 video_proxy_url 下载
选有 video_proxy_url 的最高档位。如果它同时有 audio_proxy_url,说明音视频是分离的流:分别下载后用 ffmpeg 合并;只有 video_proxy_url 时它就是完整文件。代理链接不需要 API key,也不需要额外的请求头。
1080p 及以下的档位通常是 MP4(H.264)视频加 M4A(AAC)音频,-c copy 流复制即可合成标准 MP4,无需重编码。只想要一个现成文件时,用视频媒体的 resource_proxy_url(通常清晰度较低、自带音轨);只要音频时,用音频媒体的 resource_proxy_url。
curl(配合 jq):
# 1. 获取代理链接
curl -s -X POST https://api.snapany.com/openapi/v1/youtube/proxy-download \
-H "Authorization: Bearer sk_snapany_xxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}' > post.json
# 2. 选有代理链接的最高档位(1080p 及以下)
jq '[.medias[] | select(.media_type == "video") | .variants[]? | select(.video_proxy_url)] | max_by(.quality)' post.json > variant.json
# 3. 分别下载音视频流:-f 遇到 HTTP 错误直接失败,-C - 支持断点续传
# (档位没有 audio_proxy_url 时视频文件已经完整,跳过音频那一行和第 4 步)
curl -fL -C - -o video.mp4 "$(jq -r .video_proxy_url variant.json)"
curl -fL -C - -o audio.m4a "$(jq -r .audio_proxy_url variant.json)"
# 4. 合并:流复制,不重编码
ffmpeg -i video.mp4 -i audio.m4a -c copy merged.mp4
Python:
import subprocess
import requests
response = requests.post(
"https://api.snapany.com/openapi/v1/youtube/proxy-download",
headers={"Authorization": "Bearer sk_snapany_xxx"},
json={"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"},
)
response.raise_for_status()
post = response.json()
# 有代理链接的最高档位(代理链接只在 1080p 及以下的档位出现)
video = next(media for media in post["medias"] if media["media_type"] == "video")
variant = max((v for v in video["variants"] if v.get("video_proxy_url")), key=lambda v: v["quality"])
def download(url, path):
# 不需要 API key 或请求头:代理链接本身就是访问凭证
with requests.get(url, stream=True, timeout=60) as r:
r.raise_for_status() # 如 404 payload_expired
with open(path, "wb") as f:
for chunk in r.iter_content(1 << 20):
f.write(chunk)
download(variant["video_proxy_url"], "video.mp4")
if variant.get("audio_proxy_url"):
download(variant["audio_proxy_url"], "audio.m4a")
subprocess.run(["ffmpeg", "-i", "video.mp4", "-i", "audio.m4a", "-c", "copy", "merged.mp4"], check=True)
Node.js(18+):
import { spawnSync } from 'node:child_process'
import { createWriteStream } from 'node:fs'
import { Readable } from 'node:stream'
import { pipeline } from 'node:stream/promises'
const response = await fetch('https://api.snapany.com/openapi/v1/youtube/proxy-download', {
method: 'POST',
headers: { Authorization: 'Bearer sk_snapany_xxx', 'Content-Type': 'application/json' },
body: JSON.stringify({ url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' }),
})
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`)
const post = await response.json()
// 有代理链接的最高档位(代理链接只在 1080p 及以下的档位出现)
const video = post.medias.find(media => media.media_type === 'video')
const variant = video.variants.filter(v => v.video_proxy_url).sort((a, b) => b.quality - a.quality)[0]
async function download(url, path) {
const res = await fetch(url)
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`) // 如 404 payload_expired
await pipeline(Readable.fromWeb(res.body), createWriteStream(path))
}
await download(variant.video_proxy_url, 'video.mp4')
if (variant.audio_proxy_url) {
await download(variant.audio_proxy_url, 'audio.m4a')
spawnSync('ffmpeg', ['-i', 'video.mp4', '-i', 'audio.m4a', '-c', 'copy', 'merged.mp4'], { stdio: 'inherit' })
}
大文件建议用 Range 请求下载(curl 的 -C -,或自己带 Range: bytes=… 请求头),中断后可以续传,不必从头再来。
有效期、限制与计费
有效期:代理链接自响应起至少 30 分钟、最长 1 小时有效。拿到响应就开始下载,按 30 分钟规划。
过期后代理链接返回 HTTP 404:
{ "code": "payload_expired", "message": "link has expired" }
重新调用接口拿新链接即可,重试同一条链接没有用。
有效期内代理链接返回 HTTP 403,说明 YouTube 拒绝了这次请求:
{ "code": "upstream_error", "message": "upstream refused the request", "retryable": true, "upstream_status": 403 }
这种情况很少见,重试一次通常就能成功。
限制:
- 代理链接最高 1080p。1080p 以上的档位(1440p、4K、8K)保留在响应里,但只有直链,见下方常见问题。
- 超过 3 GB 的文件不带代理链接。
- 仅支持 YouTube 链接。无法提取的链接——播放列表、频道、正在直播的视频、会员专享或已删除的视频等——返回 HTTP
400(见错误码),不扣费。
计费:返回响应后按响应内容扣费。
| 响应内容 | 扣费 |
|---|---|
有视频代理链接(档位的 video_proxy_url,或视频媒体的 resource_proxy_url) | 每 10 分钟视频 4 积分(不足 10 分钟按 10 分钟计) |
| 只有音频代理链接 | 4 积分 |
| 没有代理链接 | 1 积分 |
示例:10 分钟以内的视频 4 积分,10–20 分钟 8 积分,1 小时 24 积分。时长取自 duration 字段,缺失时按 4 积分计。上面的响应示例(duration: 754,约 12.5 分钟)消耗 8 积分。失败的调用(不支持的链接、提取失败)不扣费。
常见问题
需要自己维护住宅代理吗?
用本接口就不需要。住宅代理常见价格是每 GB $3–4,一个 20 分钟的 1080p 视频(约 270–470 MB)光代理流量就要约 $0.81–1.88,还不算维护 cookies 和 PO token 的工作量。通过本接口下载同一个视频消耗 8 积分,按积分套餐折算约 $0.0053–0.0088。
遇到「Sign in to confirm you're not a bot」怎么办?
这个报错出现在提取阶段:YouTube 把请求判定为自动化访问时会要求登录,服务器 IP 上很常见。用本接口时提取在我们这边完成,你的服务器不需要 cookies、登录账号或 PO token。
能在 AWS Lambda、EC2、VPS 上用吗?
可以。你的服务器只和 SnapAny API 及我们的下载网络通信,不直连 YouTube,所以跑在 AWS Lambda、EC2、其他云还是 VPS 上都一样。注意运行环境自身的限制:Lambda 有最长运行时间和 /tmp 容量上限,长视频建议直接流式写入对象存储(如 S3),或用 Range 分段下载。
能通过代理下载 4K 吗?
不能,代理链接最高 1080p。1440p、4K、8K 档位保留在响应里,但只有直链。YouTube 这些清晰度只提供 VP9 或 AV1 编码,文件体积是 1080p 的 3–7 倍,通常还需要转码。这些直链从家庭宽带下载一般没有问题。如果你需要通过代理下载更高清晰度,请联系我们。