抖音用户主页数据下载

下载抖音用户主页数据!

当前为 2023-07-28 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name 抖音用户主页数据下载
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2.1
  5. // @description 下载抖音用户主页数据!
  6. // @author xxmdmst
  7. // @match https://www.douyin.com/user/*
  8. // @icon https://lf1-cdn-tos.bytegoofy.com/goofy/ies/douyin_web/public/favicon.ico
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. 'use strict';
  15. let aweme_list = [];
  16. let userKey = [
  17. "昵称", "关注", "粉丝",
  18. "获赞", "抖音号", "IP属地",
  19. "年龄", "签名", "作品数", "主页"
  20. ];
  21. let userData = [];
  22.  
  23. function extractDataFromScript() {
  24. const scriptTag = document.getElementById('RENDER_DATA');
  25. if (!scriptTag) return;
  26. let data = JSON.parse(decodeURIComponent(scriptTag.innerHTML));
  27.  
  28. for (const prop in data) {
  29. if (data.hasOwnProperty(prop) && prop !== "_location" && prop !== "app") {
  30. const user = data[prop];
  31. let userInfo = user.user.user;
  32. userData.push(
  33. userInfo.nickname, userInfo.followingCount, userInfo.mplatformFollowersCount,
  34. userInfo.totalFavorited, userInfo.uniqueId, userInfo.ipLocation,
  35. userInfo.age, '"' + userInfo.desc + '"', userInfo.awemeCount, "https://www.douyin.com/user/" + userInfo.secUid
  36. );
  37. let post_data = user.post.data.map(item => Object.assign({"desc": item.desc}, item.stats,
  38. {"url": "https:" + item.video.playAddr[0].src}));
  39. aweme_list = aweme_list.concat(post_data);
  40. }
  41. }
  42. }
  43.  
  44. function createButton(title, top) {
  45. top = top === undefined ? "60px" : top;
  46. const button = document.createElement('button');
  47. button.textContent = title;
  48. button.style.position = 'fixed';
  49. button.style.right = '5px';
  50. button.style.top = top;
  51. button.style.zIndex = '90000';
  52. document.body.appendChild(button);
  53. return button
  54. }
  55.  
  56. function txt2file(txt, filename) {
  57. const blob = new Blob([txt], {type: 'text/plain'});
  58. const url = URL.createObjectURL(blob);
  59. const link = document.createElement('a');
  60. link.href = url;
  61. link.download = filename.replace(/[\/:*?"<>|]/g, "");
  62. document.body.appendChild(link);
  63. link.click();
  64. document.body.removeChild(link);
  65. URL.revokeObjectURL(url);
  66. }
  67.  
  68. function downloadData() {
  69. let text = userKey.join(",") + "\n" + userData.join(",") + "\n\n";
  70. text += "作品描述,点赞数,评论数,收藏数,分享数,下载链接\n";
  71. aweme_list.forEach(item => {
  72. text += ['"' + item.desc + '"', item.diggCount, item.commentCount,
  73. item.collectCount, item.shareCount, item.url].join(",") + "\n"
  74. });
  75. txt2file(text, userData[0] + ".csv");
  76. }
  77.  
  78. function interceptResponse() {
  79. const originalSend = XMLHttpRequest.prototype.send;
  80. XMLHttpRequest.prototype.send = function () {
  81. const self = this;
  82. this.onreadystatechange = function () {
  83. if (self.readyState === 4) {
  84. if (self._url.indexOf("/aweme/v1/web/aweme/post") > -1) {
  85. var json = JSON.parse(self.response);
  86. console.log(json.aweme_list);
  87. let post_data = json.aweme_list.map(item => Object.assign(
  88. {"desc": item.desc},
  89. {
  90. "diggCount": item.statistics.digg_count,
  91. "commentCount": item.statistics.comment_count,
  92. "collectCount": item.statistics.collect_count,
  93. "shareCount": item.statistics.share_count,
  94. },
  95. {"url": item.video.play_addr.url_list[0]}));
  96. aweme_list = aweme_list.concat(post_data);
  97. }
  98. }
  99. };
  100. originalSend.apply(this, arguments);
  101. };
  102. }
  103.  
  104. function scrollPageToBottom() {
  105. const SCROLL_DELAY = 1000; // Adjust the delay between each scroll action (in milliseconds)
  106. let scrollInterval;
  107.  
  108. function getScrollPosition() {
  109. return scrollY || pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
  110. }
  111.  
  112. function scrollToBottom() {
  113. scrollTo(0, document.body.scrollHeight);
  114. }
  115.  
  116. function hasReachedBottom() {
  117. return getScrollPosition() >= (document.body.scrollHeight - innerHeight);
  118. }
  119.  
  120. function scrollLoop() {
  121. if (!hasReachedBottom()) {
  122. scrollToBottom();
  123. } else {
  124. console.log("Reached the bottom of the page!");
  125. clearInterval(scrollInterval);
  126. }
  127. }
  128.  
  129. function startScrolling() {
  130. scrollInterval = setInterval(scrollLoop, SCROLL_DELAY);
  131. }
  132.  
  133. let button = createButton('开启自动下拉到底', '60px');
  134. button.addEventListener('click', startScrolling);
  135. }
  136.  
  137. // To start scrolling, call the function:
  138. scrollPageToBottom();
  139. interceptResponse();
  140. window.onload = () => {
  141. extractDataFromScript();
  142. let button = createButton("下载已加载数据", "81px");
  143. button.addEventListener('click', downloadData);
  144. };
  145.  
  146. })();