December 5, 2025
214 Views
Default

Guía de descarga de enlaces de video de múltiples plataformas

Este documento presenta en detalle cómo, después de obtener enlaces de video de plataformas como Douyin, TikTok, Bilibili, Xiaohongshu y Weibo, descargar correctamente los archivos de video. Se centra en resolver problemas comunes como la protección contra enlaces externos, la prevención del hotlinking y la verificación de encabezados de solicitud.

Guía de descarga de enlaces de video multiplataforma

Este documento presenta en detalle cómo descargar correctamente archivos de video después de obtener enlaces de video de plataformas como Douyin, TikTok, Bilibili, Xiaohongshu, Weibo, etc. Se centra en resolver problemas comunes como CORS, anti-hotlinking y verificación de encabezados de solicitud.

Índice


Resumen de problemas comunes

Después de obtener enlaces de video de distintas plataformas, al descargar directamente normalmente se encuentran los siguientes problemas:

Tipo de problemaDescripciónSolución
Anti-hotlinking (Referer)El servidor verifica el origen de la solicitud y rechaza orígenes no válidosEstablecer el encabezado Referer correcto
CORSLa política de seguridad del navegador bloquea solicitudes entre dominiosProxy en backend / descarga del lado del servidor
Verificación de User-AgentEl servidor verifica la identificación del clienteSimular UA de navegador
Verificación de CookieAlgunos enlaces requieren sesión iniciadaIncluir Cookie válida
Caducidad del enlaceLos enlaces de video tienen tiempo de expiraciónUsarlos a tiempo; si expiran, obtenerlos de nuevo
Restricción de IPAlgunos enlaces restringen el acceso por regiónUsar un proxy de la región correspondiente

Douyin (Douyin)

Características de los enlaces de video

Los enlaces de video de Douyin suelen presentarse en las siguientes formas:

txt
1# 播放地址 (无水印)
2https://www.douyin.com/aweme/v1/play/?video_id=xxx&line=0&file_id=xxx
3
4# CDN 地址
5https://v26-web.douyinvod.com/xxx/xxx.mp4
6
7# 带水印下载地址
8https://aweme.snssdk.com/aweme/v1/playwm/?video_id=xxx

Requisitos de descarga

Encabezado de solicitud¿Obligatorio?Valor
RefererObligatoriohttps://www.douyin.com/
User-AgentRecomendadoUA del navegador
CookieOpcionalAlgunos enlaces en alta definición lo requieren

Ejemplo de descarga en el servidor

python
1import httpx
2
3async def download_douyin_video(video_url: str, save_path: str) -> bool:
4    """
5    下载抖音视频
6
7    Args:
8        video_url: 视频播放地址
9        save_path: 保存路径
10
11    Returns:
12        是否下载成功
13    """
14    headers = {
15        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
16        "Referer": "https://www.douyin.com/",  # 必须
17        "Accept": "*/*",
18        "Accept-Encoding": "identity",  # 避免压缩,方便流式下载
19        "Range": "bytes=0-",  # 支持断点续传
20    }
21
22    async with httpx.AsyncClient(follow_redirects=True, timeout=60) as client:
23        async with client.stream("GET", video_url, headers=headers) as response:
24            if response.status_code in [200, 206]:
25                with open(save_path, "wb") as f:
26                    async for chunk in response.aiter_bytes(chunk_size=8192):
27                        f.write(chunk)
28                return True
29    return False

Problema de CORS en frontend

Los enlaces de video de Douyin no admiten CORS; las solicitudes directas desde el frontend serán bloqueadas por el navegador:

javascript
1// ❌ 错误方式 - 会被 CORS 拦截
2fetch('https://v26-web.douyinvod.com/xxx.mp4')
3  .then(res => res.blob())  // CORS error!
4
5// ✅ 正确方式 - 使用后端代理
6fetch('/api/proxy/video?url=' + encodeURIComponent(videoUrl))
7  .then(res => res.blob())
8  .then(blob => {
9    const url = URL.createObjectURL(blob);
10    const a = document.createElement('a');
11    a.href = url;
12    a.download = 'video.mp4';
13    a.click();
14  });

Notas

  1. Caducidad del enlace: Los enlaces de video de Douyin suelen ser válidos durante 24 horas
  2. Enlaces sin marca de agua: Usar play_addr en lugar de download_addr
  3. Enlaces en alta definición: Algunos videos 4K/originales son de gran tamaño; se recomienda la descarga por segmentos para evitar fallos al descargar de una sola vez

TikTok

Características de los enlaces de video

txt
1# 播放地址
2https://v16-webapp-prime.tiktok.com/video/tos/xxx.mp4
3
4# 无水印地址
5https://www.tiktok.com/aweme/v1/play/?video_id=xxx
6
7# 带水印地址
8https://v16-webapp.tiktok.com/video/tos/xxx.mp4

Requisitos de descarga

Enlaces de video de la web

Encabezado de solicitud¿Obligatorio?Valor
RefererObligatoriohttps://www.tiktok.com/
User-AgentObligatorioUA del navegador
CookieObligatorioSe requiere el campo tt_chain_token

Importante: Los enlaces de video devueltos por TikTok Web deben incluir la Cookie tt_chain_token para poder descargarse; de lo contrario, se devolverá un error 403.

Enlaces de video de la app

Encabezado de solicitud¿Obligatorio?Valor
User-AgentRecomendadoCualquier UA
CookieNo necesarioLos enlaces de la app no tienen esta restricción

Recomendación: Si puedes obtener enlaces de la app, prioriza su uso; no es necesario tratar el problema de las Cookies.

Ejemplo de descarga en el servidor

Descarga web (requiere tt_chain_token)

python
1import httpx
2
3async def download_tiktok_video_web(
4    video_url: str,
5    save_path: str,
6    tt_chain_token: str  # 必须提供
7) -> bool:
8    """
9    下载 TikTok Web 端视频
10
11    注意:
12    - Web 端链接必须携带 tt_chain_token Cookie
13    - tt_chain_token 可从浏览器或 API 响应中获取
14    """
15    headers = {
16        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
17        "Referer": "https://www.tiktok.com/",
18        "Accept": "video/webm,video/ogg,video/*;q=0.9,*/*;q=0.8",
19        "Accept-Language": "en-US,en;q=0.5",
20        "Cookie": f"tt_chain_token={tt_chain_token}",  # 必须
21        "Sec-Fetch-Dest": "video",
22        "Sec-Fetch-Mode": "no-cors",
23        "Sec-Fetch-Site": "cross-site",
24    }
25
26    async with httpx.AsyncClient(follow_redirects=True, timeout=60) as client:
27        async with client.stream("GET", video_url, headers=headers) as response:
28            if response.status_code in [200, 206]:
29                with open(save_path, "wb") as f:
30                    async for chunk in response.aiter_bytes(chunk_size=8192):
31                        f.write(chunk)
32                return True
33            elif response.status_code == 403:
34                print("下载失败: tt_chain_token 无效或缺失")
35    return False
python
1async def download_tiktok_video_app(video_url: str, save_path: str) -> bool:
2    """
3    下载 TikTok App 端视频
4
5    App 端链接无需 Cookie,直接下载即可
6    """
7    headers = {
8        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
9        "Accept": "*/*",
10    }
11
12    async with httpx.AsyncClient(follow_redirects=True, timeout=60) as client:
13        async with client.stream("GET", video_url, headers=headers) as response:
14            if response.status_code in [200, 206]:
15                with open(save_path, "wb") as f:
16                    async for chunk in response.aiter_bytes(chunk_size=8192):
17                        f.write(chunk)
18                return True
19    return False

Cómo obtener tt_chain_token

tt_chain_token es la Cookie que TikTok utiliza para la autenticación de descarga de videos; formas de obtenerla:

  1. Obtenerla desde el navegador: Abre el sitio web de TikTok, herramientas de desarrollador F12 -> Application -> Cookies -> encuentra tt_chain_token

  2. Obtenerla desde la respuesta de la API: En el encabezado Set-Cookie de algunas respuestas de la API de TikTok puede incluirse este valor

  3. Usar la API de TikHub: Los datos devueltos por la API pueden ya incluir un token disponible

python
1# 示例:从响应头提取 tt_chain_token
2def extract_tt_chain_token(response_headers: dict) -> str:
3    """从响应头中提取 tt_chain_token"""
4    cookies = response_headers.get("set-cookie", "")
5    for cookie in cookies.split(";"):
6        if "tt_chain_token=" in cookie:
7            return cookie.split("tt_chain_token=")[1].split(";")[0]
8    return ""

Restricciones regionales

Los videos de TikTok pueden tener restricciones regionales; algunos solo son accesibles en países específicos:

python
1# 使用代理下载特定地区视频
2proxies = {
3    "http://": "http://us-proxy:8080",
4    "https://": "http://us-proxy:8080",
5}
6
7async with httpx.AsyncClient(proxies=proxies) as client:
8    # ...

Notas

  1. Restricción regional: Algunos videos requieren IP de EE. UU./Europa para poder acceder
  2. Caducidad del enlace: El período de validez del enlace es de aproximadamente 24 horas
  3. Sin marca de agua: Prioriza el uso del campo downloadAddr

Bilibili (Bilibili)

Características de los enlaces de video

Los enlaces de video de Bilibili son bastante especiales: el audio y el video están separados:

txt
1# 视频流 (DASH)
2https://upos-sz-mirrorali.bilivideo.com/xxx/xxx.m4s
3
4# 音频流 (DASH)
5https://upos-sz-mirrorali.bilivideo.com/xxx/xxx.m4s
6
7# FLV 格式 (旧版)
8https://upos-sz-mirrorali.bilivideo.com/xxx/xxx.flv

Requisitos de descarga

Encabezado de solicitud¿Obligatorio?Valor
RefererObligatoriohttps://www.bilibili.com/
User-AgentRecomendadoUA del navegador
CookieHD, 4K obligatorioSESSDATA, etc.
RangeRecomendadoDescarga por segmentos

Ejemplo de descarga en el servidor

python
1import httpx
2import subprocess
3from pathlib import Path
4
5async def download_bilibili_video(
6    video_url: str,
7    audio_url: str,
8    save_path: str,
9    cookie: str = None
10) -> bool:
11    """
12    下载 B站 视频 (需要合并音视频)
13
14    Args:
15        video_url: 视频流地址
16        audio_url: 音频流地址
17        save_path: 最终保存路径
18        cookie: 可选,高清视频需要 SESSDATA
19    """
20    headers = {
21        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
22        "Referer": "https://www.bilibili.com/",  # 必须,否则 403
23        "Accept": "*/*",
24        "Accept-Encoding": "identity",
25        "Origin": "https://www.bilibili.com",
26    }
27
28    if cookie:
29        headers["Cookie"] = cookie
30
31    # 临时文件路径
32    video_temp = save_path + ".video.m4s"
33    audio_temp = save_path + ".audio.m4s"
34
35    async with httpx.AsyncClient(follow_redirects=True, timeout=120) as client:
36        # 下载视频流
37        async with client.stream("GET", video_url, headers=headers) as response:
38            if response.status_code not in [200, 206]:
39                return False
40            with open(video_temp, "wb") as f:
41                async for chunk in response.aiter_bytes(chunk_size=8192):
42                    f.write(chunk)
43
44        # 下载音频流
45        async with client.stream("GET", audio_url, headers=headers) as response:
46            if response.status_code not in [200, 206]:
47                return False
48            with open(audio_temp, "wb") as f:
49                async for chunk in response.aiter_bytes(chunk_size=8192):
50                    f.write(chunk)
51
52    # 使用 FFmpeg 合并音视频
53    try:
54        subprocess.run([
55            "ffmpeg", "-y",
56            "-i", video_temp,
57            "-i", audio_temp,
58            "-c:v", "copy",
59            "-c:a", "copy",
60            save_path
61        ], check=True, capture_output=True)
62
63        # 删除临时文件
64        Path(video_temp).unlink()
65        Path(audio_temp).unlink()
66        return True
67    except subprocess.CalledProcessError:
68        return False
Calidad¿Requiere inicio de sesión?Requisito de Cookie
360P/480PNoNinguno
720PSESSDATA
1080PSESSDATA + miembro premium
4K/HDRSESSDATA + miembro premium

Notas

  1. Debe combinarse: El formato DASH separa audio y video; se debe usar FFmpeg para combinarlos
  2. Referer obligatorio: Sin el Referer correcto se devolverá 403
  3. Caducidad del enlace: Válido durante aproximadamente 2 horas
  4. Descarga por segmentos: Para archivos grandes se recomienda usar el encabezado Range para descargar por segmentos

Xiaohongshu (Xiaohongshu)

Características de los enlaces de video

txt
1# 视频地址
2https://sns-video-bd.xhscdn.com/xxx.mp4
3https://sns-video-hw.xhscdn.com/xxx.mp4
4
5# 图片地址
6https://sns-img-bd.xhscdn.com/xxx.jpg

Requisitos de descarga

Encabezado de solicitud¿Obligatorio?Valor
RefererObligatoriohttps://www.xiaohongshu.com/
User-AgentRecomendadoUA del navegador
CookieOpcionalAlgunos contenidos lo requieren

Ejemplo de descarga en el servidor

python
1import httpx
2
3async def download_xiaohongshu_video(video_url: str, save_path: str) -> bool:
4    """
5    下载小红书视频
6
7    小红书对 Referer 检查较严格
8    """
9    headers = {
10        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
11        "Referer": "https://www.xiaohongshu.com/",  # 必须
12        "Accept": "*/*",
13        "Origin": "https://www.xiaohongshu.com",
14        "Sec-Fetch-Dest": "video",
15        "Sec-Fetch-Mode": "cors",
16        "Sec-Fetch-Site": "cross-site",
17    }
18
19    async with httpx.AsyncClient(follow_redirects=True, timeout=60) as client:
20        async with client.stream("GET", video_url, headers=headers) as response:
21            if response.status_code in [200, 206]:
22                with open(save_path, "wb") as f:
23                    async for chunk in response.aiter_bytes(chunk_size=8192):
24                        f.write(chunk)
25                return True
26    return False

Descarga de imágenes

Las imágenes de Xiaohongshu también tienen anti-hotlinking:

python
1async def download_xiaohongshu_image(image_url: str, save_path: str) -> bool:
2    """下载小红书图片"""
3    headers = {
4        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
5        "Referer": "https://www.xiaohongshu.com/",
6        "Accept": "image/avif,image/webp,image/apng,image/*,*/*;q=0.8",
7    }
8
9    async with httpx.AsyncClient(follow_redirects=True) as client:
10        response = await client.get(image_url, headers=headers)
11        if response.status_code == 200:
12            with open(save_path, "wb") as f:
13                f.write(response.content)
14            return True
15    return False

Notas

  1. Referer estricto: Debe llevar un Referer de xiaohongshu.com
  2. Nodos CDN: bd (Baidu Cloud), hw (Huawei Cloud), etc., diferentes nodos
  3. Sin marca de agua: Los enlaces devueltos por la API suelen estar sin marca de agua

Weibo (Weibo)

Características de los enlaces de video

Los enlaces de video de Weibo tienen varios formatos:

txt
1# 标准视频
2https://f.video.weibocdn.com/xxx.mp4
3
4# 直播回放
5https://live.video.weibocdn.com/xxx.flv
6
7# 高清视频
8https://video.weibo.com/media/play?fid=xxx

Requisitos de descarga

Encabezado de solicitud¿Obligatorio?Valor
RefererObligatoriohttps://weibo.com/ o https://m.weibo.cn/
User-AgentRecomendadoUA del navegador
CookieAlgunos lo requierenNecesario para videos privados

Ejemplo de descarga en el servidor

python
1import httpx
2
3async def download_weibo_video(video_url: str, save_path: str) -> bool:
4    """
5    下载微博视频
6
7    微博支持多个 Referer 域名
8    """
9    headers = {
10        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
11        "Referer": "https://weibo.com/",  # 或 https://m.weibo.cn/
12        "Accept": "*/*",
13        "Accept-Encoding": "identity",
14    }
15
16    async with httpx.AsyncClient(follow_redirects=True, timeout=60) as client:
17        async with client.stream("GET", video_url, headers=headers) as response:
18            if response.status_code in [200, 206]:
19                with open(save_path, "wb") as f:
20                    async for chunk in response.aiter_bytes(chunk_size=8192):
21                        f.write(chunk)
22                return True
23    return False

Selección de múltiples calidades

Los videos de Weibo suelen ofrecer múltiples calidades:

python
1def select_best_quality(media_info: dict) -> str:
2    """选择最高清晰度的视频链接"""
3    # 清晰度优先级
4    quality_priority = ["mp4_720p_mp4", "mp4_hd_mp4", "mp4_ld_mp4"]
5
6    playback_list = media_info.get("playback_list", [])
7
8    for quality in quality_priority:
9        for item in playback_list:
10            if item.get("quality_label") == quality:
11                return item.get("play_info", {}).get("url")
12
13    # 降级使用 stream_url
14    return media_info.get("stream_url")

Notas

  1. Dominio del Referer: Admite weibo.com y m.weibo.cn
  2. Múltiples calidades: En los datos devueltos hay varias calidades disponibles
  3. Caducidad del enlace: Algunos enlaces tienen limitaciones de tiempo

YouTube

Características de los enlaces de video

Los enlaces de video de YouTube suelen presentarse en las siguientes formas:

txt
1# 标准视频流地址
2https://rr1---sn-xxx.googlevideo.com/videoplayback?expire=xxx&ei=xxx&ip=xxx&id=xxx&itag=xxx&source=youtube&...
3
4# 自适应流地址 (DASH)
5https://manifest.googlevideo.com/api/manifest/dash/...
6
7# 直播流地址 (HLS)
8https://manifest.googlevideo.com/api/manifest/hls_variant/...

Requisitos de descarga

Restricción estricta de IP: La dirección del flujo de video de YouTube tiene una verificación extremadamente estricta de la ubicación geográfica de la IP; solo se puede descargar con éxito usando una IP de la zona de Los Ángeles, California, Estados Unidos; de lo contrario, se devolverá un error 403 Forbidden.

Encabezado de solicitud¿Obligatorio?Valor
User-AgentObligatorioUA del navegador
RefererRecomendadohttps://www.youtube.com/
OriginRecomendadohttps://www.youtube.com
IP proxyObligatorioIP de Los Ángeles, California, EE. UU.

Explicación de la restricción regional de IP

La dirección del flujo de video de YouTube se vincula a la IP del solicitante al generarse; al descargar, debe usarse una IP de la misma región:

txt
1# 视频流 URL 中包含 IP 绑定参数
2https://rr1---sn-xxx.googlevideo.com/videoplayback?
3    expire=1234567890        # 过期时间
4    &ei=xxx                  # 加密标识
5    &ip=1.2.3.4             # 绑定的 IP 地址 (关键!)
6    &id=xxx
7    &itag=137               # 视频质量标识
8    &source=youtube
9    &...

¿Por qué debe ser una IP de Los Ángeles?

  1. La mayoría de los nodos CDN de YouTube están ubicados en la costa oeste de EE. UU.
  2. Al generar la URL del flujo de video, se selecciona el CDN más cercano según la IP de la solicitud
  3. Si la región de la IP no coincide al descargar, se producirá un error 403
  4. Los Ángeles es la ubicación de los principales centros de datos de YouTube, por lo que ofrece la mejor compatibilidad

Ejemplo de descarga en el servidor

python
1import httpx
2
3async def download_youtube_video(
4    video_url: str,
5    save_path: str,
6    proxy: str = None  # 必须是美国加州洛杉矶代理
7) -> bool:
8    """
9    下载 YouTube 视频
10
11    重要:
12    - 必须使用美国加利福尼亚州洛杉矶地区的代理 IP
13    - 其他地区 IP 会返回 403 Forbidden
14    - 视频流 URL 有时效性,通常 6 小时内有效
15    """
16    headers = {
17        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
18        "Referer": "https://www.youtube.com/",
19        "Origin": "https://www.youtube.com",
20        "Accept": "*/*",
21        "Accept-Language": "en-US,en;q=0.9",
22        "Accept-Encoding": "identity",  # 避免压缩
23        "Range": "bytes=0-",  # 支持断点续传
24        "Sec-Fetch-Dest": "video",
25        "Sec-Fetch-Mode": "no-cors",
26        "Sec-Fetch-Site": "cross-site",
27    }
28
29    # 代理配置 - 必须是洛杉矶 IP
30    proxies = None
31    if proxy:
32        proxies = {
33            "http://": proxy,
34            "https://": proxy,
35        }
36
37    async with httpx.AsyncClient(
38        follow_redirects=True,
39        timeout=120,
40        proxies=proxies
41    ) as client:
42        async with client.stream("GET", video_url, headers=headers) as response:
43            if response.status_code in [200, 206]:
44                with open(save_path, "wb") as f:
45                    async for chunk in response.aiter_bytes(chunk_size=8192):
46                        f.write(chunk)
47                return True
48            elif response.status_code == 403:
49                print("下载失败: IP 地区不符合要求,请使用美国加州洛杉矶的代理")
50            elif response.status_code == 410:
51                print("下载失败: 视频链接已过期,请重新获取")
52    return False

Tratamiento de separación de audio y video

Los videos en alta definición de YouTube (1080p+) usan formato DASH, y el audio y el video están separados:

python
1import subprocess
2from pathlib import Path
3
4async def download_youtube_video_with_audio(
5    video_url: str,
6    audio_url: str,
7    save_path: str,
8    proxy: str = None
9) -> bool:
10    """
11    下载 YouTube 视频并合并音频
12
13    YouTube 1080p 及以上清晰度的视频,音频和视频是分离的
14    需要分别下载后使用 FFmpeg 合并
15    """
16    video_temp = save_path + ".video.mp4"
17    audio_temp = save_path + ".audio.m4a"
18
19    # 下载视频流
20    success = await download_youtube_video(video_url, video_temp, proxy)
21    if not success:
22        return False
23
24    # 下载音频流
25    success = await download_youtube_video(audio_url, audio_temp, proxy)
26    if not success:
27        return False
28
29    # 使用 FFmpeg 合并
30    try:
31        subprocess.run([
32            "ffmpeg", "-y",
33            "-i", video_temp,
34            "-i", audio_temp,
35            "-c:v", "copy",
36            "-c:a", "aac",
37            save_path
38        ], check=True, capture_output=True)
39
40        # 删除临时文件
41        Path(video_temp).unlink()
42        Path(audio_temp).unlink()
43        return True
44    except subprocess.CalledProcessError as e:
45        print(f"FFmpeg 合并失败: {e}")
46        return False

Ejemplo de configuración de proxy

python
1# 推荐的代理配置 - 必须是洛杉矶地区
2LA_PROXIES = [
3    "http://user:pass@la-proxy1.example.com:8080",  # 洛杉矶代理 1
4    "http://user:pass@la-proxy2.example.com:8080",  # 洛杉矶代理 2
5    "socks5://user:pass@la-socks.example.com:1080", # SOCKS5 代理
6]
7
8# 验证代理 IP 是否在洛杉矶
9async def verify_proxy_location(proxy: str) -> bool:
10    """验证代理 IP 是否在洛杉矶地区"""
11    async with httpx.AsyncClient(proxies={"https://": proxy}) as client:
12        response = await client.get("https://ipapi.co/json/")
13        data = response.json()
14
15        city = data.get("city", "")
16        region = data.get("region", "")
17        country = data.get("country_code", "")
18
19        # 检查是否在加州洛杉矶
20        is_la = (
21            country == "US" and
22            region == "California" and
23            "Los Angeles" in city
24        )
25
26        if is_la:
27            print(f"✓ 代理 IP 位于: {city}, {region}, {country}")
28        else:
29            print(f"✗ 代理 IP 位于: {city}, {region}, {country} (不符合要求)")
30
31        return is_la

Tabla de referencia de identificadores de calidad (itag)

itagresoluciónformato¿Incluye audio?
18360pMP4
22720pMP4
1371080pMP4No (requiere combinar)
2481080pWebMNo (requiere combinar)
2711440pWebMNo (requiere combinar)
3132160pWebMNo (requiere combinar)
140-audio M4ASolo audio
251-audio WebMSolo audio

Notas

  1. Restricción de IP extremadamente estricta: Debe usarse una IP de Los Ángeles, California, EE. UU.; otras regiones (incluidos otros estados de EE. UU.) pueden fallar
  2. Caducidad del enlace: La URL del flujo de video suele ser válida durante 6 horas
  3. Separación de audio y video: Las calidades superiores a 720p requieren descargar por separado el audio y el video y luego combinarlos
  4. Limitación de velocidad: YouTube limita la velocidad de descarga; para archivos grandes se recomienda la descarga por segmentos
  5. Protección de derechos de autor: Algunos videos tienen protección DRM y no se pueden descargar directamente

Solución de descarga en frontend

Debido a las restricciones de CORS, el frontend no puede descargar directamente videos de la mayoría de las plataformas. Estas son las soluciones viables:

Opción 1: Proxy en backend (recomendado)

javascript
1// 前端请求后端代理接口
2async function downloadVideo(videoUrl, platform, filename) {
3  const proxyUrl = `/api/download/video?url=${encodeURIComponent(videoUrl)}&platform=${platform}`;
4
5  const response = await fetch(proxyUrl);
6  const blob = await response.blob();
7
8  // 创建下载链接
9  const url = URL.createObjectURL(blob);
10  const a = document.createElement('a');
11  a.href = url;
12  a.download = filename || 'video.mp4';
13  document.body.appendChild(a);
14  a.click();
15  document.body.removeChild(a);
16  URL.revokeObjectURL(url);
17}

Opción 2: Abrir en una nueva ventana (disponible en algunas plataformas)

javascript
1// 部分平台链接可以直接在新窗口打开下载
2function openVideoInNewTab(videoUrl) {
3  window.open(videoUrl, '_blank');
4}

Opción 3: Usar el atributo download (escenario del mismo origen)

html
1<!-- 仅适用于同源或允许 CORS 的资源 -->
2<a href="video.mp4" download="video.mp4">下载视频</a>

Solución de descarga mediante proxy en backend

Ejemplo de proxy con FastAPI

python
1from fastapi import FastAPI, Query, Response
2from fastapi.responses import StreamingResponse
3import httpx
4
5app = FastAPI()
6
7# 各平台的请求头配置
8PLATFORM_HEADERS = {
9    "douyin": {
10        "Referer": "https://www.douyin.com/",
11        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
12    },
13    "tiktok": {
14        "Referer": "https://www.tiktok.com/",
15        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
16    },
17    "bilibili": {
18        "Referer": "https://www.bilibili.com/",
19        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
20    },
21    "xiaohongshu": {
22        "Referer": "https://www.xiaohongshu.com/",
23        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
24    },
25    "weibo": {
26        "Referer": "https://weibo.com/",
27        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
28    },
29}
30
31
32@app.get("/api/download/video")
33async def proxy_video(
34    url: str = Query(..., description="视频 URL"),
35    platform: str = Query(..., description="平台标识"),
36):
37    """
38    视频代理下载接口
39
40    解决前端跨域和防盗链问题
41    """
42    headers = PLATFORM_HEADERS.get(platform, {})
43
44    async def video_stream():
45        async with httpx.AsyncClient(follow_redirects=True, timeout=120) as client:
46            async with client.stream("GET", url, headers=headers) as response:
47                async for chunk in response.aiter_bytes(chunk_size=8192):
48                    yield chunk
49
50    return StreamingResponse(
51        video_stream(),
52        media_type="video/mp4",
53        headers={
54            "Content-Disposition": "attachment; filename=video.mp4",
55            "Access-Control-Allow-Origin": "*",  # 允许跨域
56        }
57    )
58
59
60@app.get("/api/download/image")
61async def proxy_image(
62    url: str = Query(..., description="图片 URL"),
63    platform: str = Query(..., description="平台标识"),
64):
65    """图片代理下载接口"""
66    headers = PLATFORM_HEADERS.get(platform, {})
67
68    async with httpx.AsyncClient(follow_redirects=True) as client:
69        response = await client.get(url, headers=headers)
70
71        return Response(
72            content=response.content,
73            media_type=response.headers.get("content-type", "image/jpeg"),
74            headers={
75                "Access-Control-Allow-Origin": "*",
76            }
77        )

Ejemplo de descarga con progreso

python
1import httpx
2from tqdm import tqdm
3
4async def download_with_progress(url: str, save_path: str, headers: dict) -> bool:
5    """带进度条的下载"""
6    async with httpx.AsyncClient(follow_redirects=True, timeout=120) as client:
7        async with client.stream("GET", url, headers=headers) as response:
8            total = int(response.headers.get("content-length", 0))
9
10            with open(save_path, "wb") as f:
11                with tqdm(total=total, unit="B", unit_scale=True, desc="下载中") as pbar:
12                    async for chunk in response.aiter_bytes(chunk_size=8192):
13                        f.write(chunk)
14                        pbar.update(len(chunk))
15
16            return True
17    return False

Resumen

Tabla rápida de puntos clave de descarga por plataforma

PlataformaRefererRequisito de CookieTratamiento especialCaducidad del enlace
Douyinhttps://www.douyin.com/OpcionalNinguno24 horas
TikTok Webhttps://www.tiktok.com/Obligatorio tt_chain_tokenRequiere proxy regional1-6 horas
TikTok AppNo necesarioNo necesarioUso recomendadoMás larga
Bilibilihttps://www.bilibili.com/Para HD es obligatorio SESSDATALa separación de audio y video requiere combinar2 horas
Xiaohongshuhttps://www.xiaohongshu.com/OpcionalNingunoMás larga
Weibohttps://weibo.com/Algunos lo requierenMúltiples calidadesMás larga
YouTubehttps://www.youtube.com/No necesarioIP de Los Ángeles obligatoria + separación de audio y video6 horas

Solución de problemas comunes

Código de errorPosible causaSolución
403 ForbiddenReferer incorrecto o ausenteVerificar el encabezado Referer
403 ForbiddenTikTok sin tt_chain_tokenAñadir Cookie o usar enlace de la app
403 ForbiddenLa IP de YouTube no coincide con la regiónUsar un proxy de Los Ángeles, California, EE. UU.
404 Not FoundEnlace caducadoObtener el enlace de nuevo
410 GoneEnlace de YouTube caducadoObtener de nuevo la URL del flujo de video
CORS ErrorRestricción de CORS del navegadorUsar proxy en backend
TimeoutProblemas de red o archivo demasiado grandeAumentar el tiempo de espera, descargar por segmentos

Mejores prácticas

  1. Establecer siempre Referer: Es un requisito necesario para la mayoría de las plataformas
  2. Usar proxy en backend: La mejor solución para resolver problemas de CORS en frontend
  3. Gestionar la caducidad del enlace: Usar el enlace a tiempo; si expira, obtenerlo de nuevo
  4. Admitir reanudación de descargas: Para archivos grandes, usar el encabezado Range para descargar por segmentos
  5. Reintentos ante errores: Implementar un mecanismo de reintento cuando la red sea inestable

Contáctanos

Si después de seguir las instrucciones de este documento aún no puedes descargar el video con éxito, contacta al servicio de atención al cliente para obtener ayuda:

Al contactar al servicio de atención al cliente, proporciona la siguiente información para que podamos ayudarte más rápidamente:

  1. Nombre de la plataforma: Douyin/TikTok/Bilibili/Xiaohongshu/Weibo/YouTube
  2. Enlace del video: URL original de la página del video
  3. Mensaje de error: código de error completo y descripción del error
  4. Configuración de encabezados de solicitud: información de Referer, Cookie, etc. que estás usando
  5. Información del proxy: si usas proxy, proporciona la región del proxy

Enjoyed this article?

Share it with your friends and colleagues!

Default
Last updated: May 15, 2026
相关文章
正在检查服务状态...
多平台视频链接下载指南 - TikHub.io