December 5, 2025
214 Views
Default

다중 플랫폼 비디오 링크 다운로드 가이드

이 문서는 Douyin, TikTok, Bilibili, Xiaohongshu, Weibo 등 플랫폼에서 비디오 링크를 가져온 후, 비디오 파일을 올바르게 다운로드하는 방법을 자세히 소개합니다. 핵심은 크로스 도메인, 핫링크 방지, 요청 헤더 검증 등 흔히 발생하는 문제를 해결하는 것입니다.

다중 플랫폼 비디오 링크 다운로드 가이드

이 문서는 Douyin, TikTok, Bilibili, Xiaohongshu, Weibo 등 플랫폼에서 비디오 링크를 가져온 후, 비디오 파일을 올바르게 다운로드하는 방법을 자세히 소개합니다. 핵심은 크로스 도메인, 핫링크 방지, 요청 헤더 검증 등 흔한 문제를 해결하는 것입니다.

목차


공통 문제 개요

각 플랫폼에서 비디오 링크를 가져온 후, 직접 다운로드하면 보통 다음과 같은 문제를 만나게 됩니다:

문제 유형설명해결 방안
핫링크 방지 (Referer)서버가 요청 출처를 검사하여 불법 출처를 거부올바른 Referer 헤더 설정
크로스 도메인 (CORS)브라우저 보안 정책이 크로스 도메인 요청을 차단백엔드 프록시 / 서버 측 다운로드
User-Agent 검증서버가 클라이언트 식별자를 검사브라우저 UA 모방
Cookie 검증일부 링크는 로그인 상태 필요유효한 Cookie 포함
링크 유효 시간비디오 링크에는 만료 시간이 있음즉시 사용, 만료 시 재획득
IP 제한일부 링크는 지역 접근 제한해당 지역 프록시 사용

Douyin

비디오 링크 특징

Douyin 비디오 링크는 보통 다음과 같은 형태입니다:

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

다운로드 요구사항

요청 헤더필수 여부
Referer필수https://www.douyin.com/
User-Agent권장브라우저 UA
Cookie선택일부 고화질 링크에 필요

서버 측 다운로드 예시

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

프런트엔드 크로스 도메인 문제

Douyin 비디오 링크는 CORS를 지원하지 않으므로, 프런트엔드에서 직접 요청하면 브라우저에 의해 차단됩니다:

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  });

주의사항

  1. 링크 유효 시간: Douyin 비디오 링크는 보통 24시간 내에 유효합니다
  2. 워터마크 없는 링크: play_addr를 사용하고 download_addr는 사용하지 마세요
  3. 고화질 링크: 일부 4K/원본 화질 비디오는 용량이 크므로, 한 번에 다운로드 실패를 피하기 위해 분할 다운로드를 권장합니다

TikTok

비디오 링크 특징

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

다운로드 요구사항

Web端 비디오 링크

요청 헤더필수 여부
Referer필수https://www.tiktok.com/
User-Agent필수브라우저 UA
Cookie필수tt_chain_token 필드 필요

중요: TikTok Web端에서 반환된 비디오 링크는 다운로드하려면 반드시 tt_chain_token Cookie를 포함해야 하며, 그렇지 않으면 403 오류가 반환됩니다.

App端 비디오 링크

요청 헤더필수 여부
User-Agent권장임의의 UA
Cookie불필요App端 링크에는 이 제한이 없음

권장: App端 링크를 얻을 수 있다면 우선적으로 App端 링크를 사용하세요. Cookie 문제를 처리할 필요가 없습니다.

서버 측 다운로드 예시

Web端 다운로드 (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

tt_chain_token 획득 방법

tt_chain_token은 TikTok이 비디오 다운로드 인증에 사용하는 Cookie로, 획득 방법은 다음과 같습니다:

  1. 브라우저에서 획득: TikTok 웹사이트를 열고, F12 개발자 도구 -> Application -> Cookies -> tt_chain_token 찾기

  2. API 응답에서 획득: 일부 TikTok API 응답의 Set-Cookie 헤더에 이 값이 포함될 수 있음

  3. TikHub API 사용: API 반환 데이터에 사용 가능한 token이 이미 포함되어 있을 수 있음

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 ""

지역 제한

TikTok 비디오는 지역 제한이 있을 수 있으며, 일부 비디오는 특정 국가에서만 접근 가능합니다:

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    # ...

주의사항

  1. 지역 제한: 일부 비디오는 미국/유럽 IP가 있어야 접근 가능
  2. 링크 유효 시간: 링크 유효 기간은 약 24시간
  3. 워터마크 없음: downloadAddr 필드를 우선 사용

Bilibili

비디오 링크 특징

B站 비디오 링크는 비교적 특수하며, 오디오와 비디오가 분리되어 있습니다:

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

다운로드 요구사항

요청 헤더필수 여부
Referer필수https://www.bilibili.com/
User-Agent권장브라우저 UA
Cookie고화질, 4K 필수SESSDATA 등
Range권장분할 다운로드

서버 측 다운로드 예시

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

화질과 Cookie의 관계

화질로그인 필요 여부Cookie 요구사항
360P/480P아니오없음
720PSESSDATA
1080PSESSDATA + 대회원
4K/HDRSESSDATA + 대회원

주의사항

  1. 반드시 병합: DASH 형식은 오디오와 비디오가 분리되어 있으므로 FFmpeg로 병합해야 함
  2. Referer 필수: 올바른 Referer가 없으면 403 반환
  3. 링크 유효 시간: 약 2시간 유효
  4. 분할 다운로드: 대용량 파일은 Range 헤더를 사용한 분할 다운로드 권장

Xiaohongshu

비디오 링크 특징

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

다운로드 요구사항

요청 헤더필수 여부
Referer필수https://www.xiaohongshu.com/
User-Agent권장브라우저 UA
Cookie선택일부 콘텐츠에 필요

서버 측 다운로드 예시

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

이미지 다운로드

Xiaohongshu 이미지도 핫링크 방지가 있습니다:

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

주의사항

  1. Referer 엄격: 반드시 xiaohongshu.com의 Referer를 포함해야 함
  2. CDN 노드: bd(Baidu Cloud), hw(Huawei Cloud) 등 서로 다른 노드
  3. 워터마크 없음: API가 반환하는 링크는 보통 워터마크가 없음

Weibo

비디오 링크 특징

Weibo 비디오 링크 형식은 여러 가지입니다:

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

다운로드 요구사항

요청 헤더필수 여부
Referer필수https://weibo.com/ 또는 https://m.weibo.cn/
User-Agent권장브라우저 UA
Cookie일부 필요비공개 비디오에 필요

서버 측 다운로드 예시

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

다중 화질 선택

Weibo 비디오는 보통 여러 화질을 제공합니다:

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")

주의사항

  1. Referer 도메인: weibo.comm.weibo.cn 지원
  2. 다중 화질: 반환 데이터에 여러 화질 선택지가 있음
  3. 링크 유효성: 일부 링크는 유효 기간 제한이 있음

YouTube

비디오 링크 특징

YouTube 비디오 링크는 보통 다음과 같은 형태입니다:

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/...

다운로드 요구사항

엄격한 IP 제한: YouTube 비디오 스트림 주소는 IP 지리 위치에 대해 매우 엄격한 검증을 하며, 미국 캘리포니아주 로스앤젤레스 지역 IP를 사용해야만 성공적으로 다운로드할 수 있습니다. 그렇지 않으면 403 Forbidden 오류가 반환됩니다.

요청 헤더필수 여부
User-Agent필수브라우저 UA
Referer권장https://www.youtube.com/
Origin권장https://www.youtube.com
프록시 IP필수미국 캘리포니아주 로스앤젤레스 IP

IP 지역 제한 설명

YouTube의 비디오 스트림 주소는 생성 시 요청자의 IP 주소에 바인딩되며, 다운로드 시 반드시 동일한 지역의 IP를 사용해야 합니다:

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    &...

왜 반드시 로스앤젤레스 IP여야 하나요?

  1. YouTube의 대부분 CDN 노드는 미국 서부 해안에 위치함
  2. 비디오 스트림 URL 생성 시 요청 IP에 따라 가장 가까운 CDN이 선택됨
  3. 다운로드 시 IP 지역이 일치하지 않으면 403 오류가 발생함
  4. 로스앤젤레스는 YouTube의 주요 데이터센터 위치로, 호환성이 가장 좋음

서버 측 다운로드 예시

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

오디오/비디오 분리 처리

YouTube 고화질 비디오(1080p+)는 DASH 형식을 사용하며, 오디오와 비디오가 분리되어 있습니다:

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

프록시 설정 예시

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

화질 식별자(itag) 대응표

itag해상도형식오디오 포함 여부
18360pMP4
22720pMP4
1371080pMP4아니오 (병합 필요)
2481080pWebM아니오 (병합 필요)
2711440pWebM아니오 (병합 필요)
3132160pWebM아니오 (병합 필요)
140-M4A 오디오오디오만
251-WebM 오디오오디오만

주의사항

  1. IP 제한이 매우 엄격함: 반드시 미국 캘리포니아주 로스앤젤레스 IP를 사용해야 하며, 다른 지역(미국의 다른 주 포함)은 실패할 수 있음
  2. 링크 유효 시간: 비디오 스트림 URL은 보통 6시간 내에 유효
  3. 오디오/비디오 분리: 720p 이상의 화질은 오디오와 비디오를 각각 다운로드한 후 병합해야 함
  4. 속도 제한: YouTube는 다운로드 속도에 제한이 있으므로, 대용량 파일은 분할 다운로드 권장
  5. 저작권 보호: 일부 비디오는 DRM 보호가 있어 직접 다운로드할 수 없음

프런트엔드 다운로드 방식

CORS 제한으로 인해 프런트엔드에서는 대부분 플랫폼의 비디오를 직접 다운로드할 수 없습니다. 가능한 방식은 다음과 같습니다:

방식 1: 백엔드 프록시(권장)

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}

방식 2: 새 창에서 열기(일부 플랫폼에서 사용 가능)

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

방식 3: download 속성 사용(동일 출처 시나리오)

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

백엔드 프록시 다운로드 방식

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        )

진행률이 있는 다운로드 예시

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

요약

각 플랫폼 다운로드 핵심 포인트 빠른 참고표

플랫폼RefererCookie 요구사항특수 처리링크 유효 시간
Douyinhttps://www.douyin.com/선택없음24시간
TikTok Webhttps://www.tiktok.com/필수 tt_chain_token지역 프록시 필요1-6시간
TikTok App불필요불필요사용 권장
B站https://www.bilibili.com/고화질은 SESSDATA 필수오디오/비디오 분리 시 병합 필요2시간
Xiaohongshuhttps://www.xiaohongshu.com/선택없음
Weibohttps://weibo.com/일부 필요다중 화질
YouTubehttps://www.youtube.com/불필요반드시 로스앤젤레스 IP + 오디오/비디오 분리6시간

흔한 오류 점검

오류 코드가능한 원인해결 방안
403 ForbiddenReferer 오류 또는 누락Referer 헤더 확인
403 ForbiddenTikTok의 tt_chain_token 누락Cookie 추가 또는 App端 링크 사용
403 ForbiddenYouTube IP 지역 불일치미국 캘리포니아주 로스앤젤레스 프록시 사용
404 Not Found링크 만료링크 재획득
410 GoneYouTube 링크 만료비디오 스트림 URL 재획득
CORS Error브라우저 크로스 도메인 제한백엔드 프록시 사용
시간 초과네트워크 문제 또는 파일이 너무 큼타임아웃 증가, 분할 다운로드

모범 사례

  1. 항상 Referer 설정: 대부분 플랫폼의 필수 조건입니다
  2. 백엔드 프록시 사용: 프런트엔드 CORS 문제를 해결하는 최선의 방법입니다
  3. 링크 유효 시간 처리: 링크를 즉시 사용하고, 만료되면 재획득하세요
  4. 이어받기 지원: 대용량 파일은 Range 헤더를 사용해 분할 다운로드하세요
  5. 오류 재시도: 네트워크가 불안정할 때 재시도 메커니즘을 구현하세요

문의하기

이 문서의 안내에 따라 작업했음에도 비디오를 성공적으로 다운로드할 수 없다면, 고객센터에 문의하여 도움을 받으세요:

고객센터에 문의할 때는 더 빠른 도움을 위해 아래 정보를 제공해 주세요:

  1. 플랫폼 이름: Douyin/TikTok/B站/Xiaohongshu/Weibo/YouTube
  2. 비디오 링크: 원본 비디오 페이지 URL
  3. 오류 정보: 전체 오류 코드와 오류 설명
  4. 요청 헤더 설정: 사용한 Referer, Cookie 등의 정보
  5. 프록시 정보: 프록시를 사용한 경우 프록시 지역을 제공해 주세요

Enjoyed this article?

Share it with your friends and colleagues!

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