抖音无水印视频解析原理及实现

抖音无水印视频下载其实很简单,自己手动也可以获取无水印视频。
浏览器调式模式F12打开链接,查看网络请求,如图
image.png

  1. 首先获取分享短链接
    抖音复制链接,得到:「时间也不早啦,洗漱完就早点休息吧~ https://v.douyin.com/eRD1x1v/ 复制此lian接,打开Dou音搜索,矗接观看視频!」
  2. 将短链接在网页上打开
    首先复制你要下载的视频链接在电脑的浏览器打开,在浏览器上输入这个链接以后,可以看到页面进行了一次跳转,刚才的短连接也变成了另一个长链接(这里其实是通过 302 进行了重定向):
    https://www.iesdouyin.com/share/video/6535309780305579272/?region=CN&mid=6535310190042942211&u_code=lgmf23ik&titleType=title&did=40591980672&iid=2252231182654638&timestamp=1615379860&app=aweme&utm_campaign=client_share&utm_medium=ios&tt_from=copy&utm_source=copy
    这时按一下键盘的F12或者右键选择审查元素,选择 Network 这个标签,然后选择 Media 按 clear 之后按 F5 刷新。
    得到播放地址:
    https://aweme.snssdk.com/aweme/v1/playwm/?video_id=aabe577a58794e00a53895f73881dc12&ratio=720p&line=0

然后把地址中playwm中的wm去掉得到地址,wm就是 watermark 水印的意思。
https://aweme.snssdk.com/aweme/v1/play/?video_id=aabe577a58794e00a53895f73881dc12&ratio=720p&line=0

复制浏览器中打开,得到的视频就是无水印视频,下载右键视频另存为即可。
许多APP,小程序或在线工具解析原理就是把以上流程用程序实现

程序实现

抓包分析接口

获取视频信息:
https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=**视频ID**&dytk=**dytk**
其中参数dytk获取方式如下(使用手机端UA):
https://www.iesdouyin.com/share/video/**视频ID**/?mid=1

Python实现功能

基于Python + Flask 的去水印 API
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# -*- encoding: utf-8 -*-

# 导入需求模块
import requests
from flask import Flask, request, jsonify
import re

headers = {
'User-Agent':
'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36'
}

app = Flask(__name__)

# jsonify返回中文直接显示,不加这一句的话会编码Unicode
app.config['JSON_AS_ASCII'] = False

# 设置允许跨域
@app.after_request
def cors(environ):
environ.headers['Access-Control-Allow-Origin'] = '*'
environ.headers['Access-Control-Allow-Method'] = '*'
environ.headers[
'Access-Control-Allow-Headers'] = 'x-requested-with,content-type'
return environ

# 设置404返回模板
@app.errorhandler(404)
def not_found(error):
resp = {'status_code': '404'}
return jsonify(resp), 404

# 无参数
@app.route('/', methods=['GET', 'POST'])
def index():
resp = {'status_code': '404'}
return jsonify(resp)

# @NAME : 抖音解析去水印视频
# @URL : /douyin/parse?id=6535309780305579272
# @URL : /douyin/parse?url=https://v.douyin.com/eRD1x1v/
@app.route('/douyin/parse', methods=['GET'])
def douyin_parsing():
id = request.args.get('id')
url = request.args.get('url')
if id:
resp = parse_by_id(id)
elif url:
resp = parse_by_url(url)
else:
resp = {'error': '参数错误!'}
return jsonify(resp)

def get_real_addr(uri):
url = 'https://aweme.snssdk.com/aweme/v1/play/?video_id={}&ratio=720p&line=0'.format(
uri)
try:
r = requests.head(url, headers=headers, allow_redirects=False)
addr = r.headers['Location']
return addr
except Exception:
return 'error'


def parse_by_url(url):
if '/share/video/' in url:
id = re.findall(r'share/video/(\d+)/?\??', url)[0]
else:
try:
r = requests.head(url, headers=headers, allow_redirects=False)
id = re.findall(r'share/video/(\d+)/?\??',
r.headers['Location'])[0]
except Exception:
return {'error': 'URL错误!'}
return parse_by_id(id)


def parse_by_id(id):
url = 'https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=' + id
try:
r = requests.get(url).json()
video = r['item_list'][0]
res = {}
res['desc'] = video['desc']
res['comment'] = video['statistics']['comment_count']
res['digg'] = video['statistics']['digg_count']
res['author'] = video['author']['nickname']
res['music'] = video['music']['play_url']['uri']
res['cover'] = video['video']['cover']['url_list'][0]
videouri = video['video']['play_addr']['uri']
res['video'] = get_real_addr(videouri)
return res
except Exception:
return {'error': '出错了!'}


# 本地调试
if __name__ == "__main__":
app.run(host='127.0.0.1', port=2222)

DEMO

基于PHP Curl:
抖音去水印 程序源于HammCn

Python + Flask 版本:
抖音作品解析

聚合网上的vip视频解析接口:
VIP视频云解析 程序源于佰阅