抖音自带的数据导出功能只能导出30天内的最后100条视频。当数据量大时,统计分析每月视频将非常麻烦。因此编写以下脚本用于直接导出视频数据到指定日期,非常实用方便。
脚本仅供学习参考,不得用于商业违法行为。如有侵权请联系删除。
加载方式将代码保存为js文件后再请上网搜索“油猴导入脚本”、“篡改猴导入脚本”。

以下油猴脚本不再更新,如有需要可以看看下一篇代码
// ==UserScript==
// @name 导出抖音视频数据
// @namespace doupoa.site
// @version 1.2
// @description 导出抖音视频数据
// @author doupoa
// @copyright 2024,doupoa.site
// @license MIT
// @match https://creator.douyin.com/creator-micro/content/manage
// @icon https://p1-ecda.byteimg.com/tos-cn-i-n15nrygpm8/563a38e870c441b8af75c0c8c38b1a39~tplv-n15nrygpm8-image.image
// @grant none
// ==/UserScript==
(function () {
'use strict';
var videoData = "视频标题,发布时间,播放量,点赞量,评论量,转发量,状态,视频ID,链接\r\n";
var deadline = '';
function formatDate(value) {
try {
value = value.replace("年", "-").replace("月", "-").replace("日", "")
return Date.parse(value)
} catch {
return value
}
}
// 视频标题,发布时间,播放量,点赞量,评论量,转发量,状态,视频ID,链接
function parseVideoData(data) {
data = JSON.parse(data);
return new Promise((resolve) => {
for (var i = 0; i < data.aweme_list.length; i++) {
let title = data.aweme_list[i].desc.replace(/[\r\n]/g, "") //视频标题 去除回车换行符
let createTime = new Date(data.aweme_list[i].create_time * 1000) //发布时间
let playCount = data.aweme_list[i].statistics.play_count // 播放量
let diggCount = data.aweme_list[i].statistics.digg_count //点赞量
let commentCount = data.aweme_list[i].statistics.comment_count //评论量
let forwardCount = data.aweme_list[i].statistics.forward_count //转发量
let status = data.aweme_list[i].status.private_status ? "私密" : "已发布" //状态
let videoID = data.aweme_list[i].aweme_id //视频ID
let shareUrl = data.aweme_list[i].share_url //视频分享链接
if (createTime < formatDate(deadline)) { // 视频创建时间小于截止日期,退出循环。
resolve(-1) // 返回自定义状态码,终止循环
} else {
videoData += title + "," + createTime.toLocaleString() + "," + playCount + "," + diggCount + "," + commentCount + "," + forwardCount + "," + status + "," + videoID + "," + shareUrl + "\r\n"
}
}
resolve(data.max_cursor)
})
}
function doGet(url) {
return new Promise((resolve, reject) => {
let req = new XMLHttpRequest();
req.open("Get", url);
req.send();
req.onload = function () {
if (req.status == 200) {
resolve(req.response);
}
else {
reject(Error("Network Error"));
}
};
req.onerror = function () {
reject(Error("Network Error"));
};
});
}
function export_csv(data, name) {
const blob = new Blob(["\ufeff" + data], {
type: 'text/csv;charset=utf-8;'
});
// 如果是 IE 浏览器
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, name + ".csv");
} else {
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.href = url;
link.setAttribute('download', name + ".csv");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
async function main() {
deadline = document.getElementById('deadline').value;
if (deadline == '') {
alert("请先设置数据截止日期");
return;
} else {
var cursor = 0 // 游标
while (true) {
let code = await parseVideoData(await doGet("https://creator.douyin.com/web/api/media/aweme/post/?count=20&max_cursor=" + cursor))
if (code != -1) { // 自定义状态码为-1时即代表数据已达截止日期
cursor = code;
} else if (code == cursor) { //返回的游标跟上一返回游标一致时退出循环。
break
} else {
break
}
}
let date = new Date();
export_csv(videoData, date.toLocaleString());
}
}
function createElement() {
var div_root = document.createElement('div');
div_root.className = "container-QT0YYw";
var div_node_1 = document.createElement('div');
div_node_1.className = "info-content";
var div_node_1_1 = document.createElement('div')
div_node_1_1.className = "profit-info-yh9YMK";
var div_node_1_2 = document.createElement('div');
div_node_1_2.className = "profit-title-JwUHmS";
div_node_1_2.textContent = "导出视频数据"
var div_node_1_2_1 = document.createElement('div');
div_node_1_2_1.className = "main-text-qYVJkl";
var div_node_1_2_1_1 = document.createElement('div');
div_node_1_2_1_1.textContent = "数据截止于"
var div_node_1_2_1_2 = document.createElement('input')
div_node_1_2_1_2.type = "date"
div_node_1_2_1_2.id = "deadline"
div_node_1_2_1_2.name = "deadline"
var div_node_2 = document.createElement('div');
div_node_2.className = "btn-group--1izHb";
var div_node_2_1 = document.createElement('button');
div_node_2_1.className = "semi-button semi-button-tertiary semi-button-light";
div_node_2_1.type = "button";
div_node_2_1.addEventListener("click", main);
var div_node_2_1_1 = document.createElement('span');
div_node_2_1_1.className = "semi-button-content"
div_node_2_1_1.textContent = "导出";
div_node_2_1.appendChild(div_node_2_1_1);
div_node_2.appendChild(div_node_2_1);
div_node_1_2_1.appendChild(div_node_1_2_1_1);
div_node_1_2_1.appendChild(div_node_1_2_1_2);
div_node_1_1.appendChild(div_node_1_2);
div_node_1_1.appendChild(div_node_1_2_1);
div_node_1.appendChild(div_node_1_1);
div_root.appendChild(div_node_1);
div_root.appendChild(div_node_2);
var doc = document.getElementsByClassName("profit-container-VUnTzL")[0]
doc.appendChild(div_root);
/*
上述构造元素如下:
<div class="container--2UxXM">
<div class="info-content">
<div class="profit-info--4SoCI">
<div class="profit-title--pXNAj">导出视频数据</div>
<div class="main-text--2_OUZ">
<div>数据截止于</div>
<input type="date" id="start" name="deadline" value="">
</div>
</div>
</div>
<div class="btn-group--1izHb">
<button class="semi-button semi-button-tertiary semi-button-light" type="button">
<span class="semi-button-content">导出</span>
</button>
</div>
</div>
*/
}
window.setTimeout(() => {
createElement(); // 创建用户界面节点
}, 8000);
})();
以下版本的代码直接在网页端使用F12打开开发者工具,随后粘贴代码回车运行即可。
(function() {
'use strict';
var videoData = "视频标题,发布时间,播放量,点赞量,评论量,转发量,状态,视频ID,链接\r\n";
var deadline = '';
function formatDate(value) {
try {
value = value.replace("年", "-").replace("月", "-").replace("日", "")
return Date.parse(value)
} catch {
return value
}
}
// 视频标题,发布时间,播放量,点赞量,评论量,转发量,状态,视频ID,链接
function parseVideoData(data) {
data = JSON.parse(data);
return new Promise((resolve)=>{
for (var i = 0; i < data.aweme_list.length; i++) {
let title = data.aweme_list[i].desc.replace(/[\r\n]/g, "")
//视频标题 去除回车换行符
let createTime = new Date(data.aweme_list[i].create_time * 1000)
//发布时间
let playCount = data.aweme_list[i].statistics.play_count
// 播放量
let diggCount = data.aweme_list[i].statistics.digg_count
//点赞量
let commentCount = data.aweme_list[i].statistics.comment_count
//评论量
let forwardCount = data.aweme_list[i].statistics.forward_count
//转发量
let status = data.aweme_list[i].status.private_status ? "私密" : "已发布"
//状态
let videoID = data.aweme_list[i].aweme_id
//视频ID
let shareUrl = data.aweme_list[i].share_url
//视频分享链接
if (createTime < deadline && !("is_pinned" in data.aweme_list[i])) {
// 视频创建时间小于截止日期,退出循环。
console.log(createTime + "<" + deadline)
resolve(-1)
// 返回自定义状态码,终止循环
} else {
console.log(createTime.toLocaleString())
videoData += title + "," + createTime.toLocaleString() + "," + playCount + "," + diggCount + "," + commentCount + "," + forwardCount + "," + status + "," + videoID + "," + shareUrl + "\r\n"
}
}
resolve(data.max_cursor)
}
)
}
function doGet(url) {
return new Promise((resolve,reject)=>{
let req = new XMLHttpRequest();
req.open("Get", url);
req.send();
req.onload = function() {
if (req.status == 200) {
resolve(req.response);
} else {
reject(Error("Network Error"));
}
}
;
req.onerror = function() {
reject(Error("Network Error"));
}
;
}
);
}
function export_csv(data, name) {
const blob = new Blob(["\ufeff" + data],{
type: 'text/csv;charset=utf-8;'
});
// 如果是 IE 浏览器
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, name + ".csv");
} else {
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.href = url;
link.setAttribute('download', name + ".csv");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
async function main(time) {
console.log("开始运行..")
deadline = new Date(time);
if (deadline == '') {
alert("请先设置数据截止日期");
return;
} else {
console.log("截止日期为:" + deadline)
var cursor = 0
// 游标
while (true) {
let code = await parseVideoData(await doGet("https://creator.douyin.com/web/api/media/aweme/post/?count=20&max_cursor=" + cursor))
console.log("当前游标:"+code)
if (code != -1) {
// 自定义状态码为-1时即代表数据已达截止日期
cursor = code;
} else if (code == cursor) {
//返回的游标跟上一返回游标一致时退出循环。
console.log("游标一致退出循环")
break
} else{
console.log("游标为:"+code+",退出循环")
break
}
}
let date = new Date();
export_csv(videoData, date.toLocaleString());
}
}
let time = "2025/01/01 00:00";
// 数据截止日期,格式为"年/月/日 时:分" 例如:"2025/02/01 00:00" 必须按照格式修改,否则无法识别
main(time);
}
)();
发表回复