doupoa
一个不甘落后的热血青年!
Ping通途说

视频数据导出-抖音创作者服务中心

warning 内容具有时效性
脚本通过class类样式获取页面相关元素,若目标网站使用的样式发生重大调整(如其使用的SemiUI框架进行升级),其ClassID会改变。因此需要经常更新样式。本文作者不保证能随时更新,如有需要请联系更新! 版本:1.2 最近更新日期:2024/11/13

抖音自带的数据导出功能只能导出30天内的最后100条视频。当数据量大时,统计分析每月视频将非常麻烦。因此编写以下脚本用于直接导出视频数据到指定日期,非常实用方便。

脚本仅供学习参考,不得用于商业违法行为。如有侵权请联系删除。

加载方式将代码保存为js文件后再请上网搜索“油猴导入脚本”、“篡改猴导入脚本”。

https://doupoa.site/wp-content/uploads/2023/11/1698985328-image-1024x355.png
// ==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);
})();

赞赏

doupoa

文章作者

诶嘿

发表回复

textsms
account_circle
email

  • 11

    为啥用不了

    1 月前 回复
    • doupoa博主

      @11: 脚本已更新,请覆盖旧脚本并重试

      1 周前

Ping通途说

视频数据导出-抖音创作者服务中心
warning 内容具有时效性脚本通过class类样式获取页面相关元素,若目标网站使用的样式发生重大调整(如其使用的SemiUI框架进行升级),其ClassID会改变。因此需要经常更新样式。本文作者不…
扫描二维码继续阅读
2023-11-03

Optimized by WPJAM Basic