Greasy Fork is available in English.

单品分析_爆品指数_人群分析对比

云图扩展工具

  1. // ==UserScript==
  2. // @name 单品分析_爆品指数_人群分析对比
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1.2
  5. // @description 云图扩展工具
  6. // @author siji-Xian
  7. // @match *://yuntu.oceanengine.com/yuntu_brand/product/productOverview/productAnalysis/crowd*
  8. // @icon https://lf3-static.bytednsdoc.com/obj/eden-cn/prhaeh7pxvhn/yuntu/yuntu-logo_default.svg
  9. // @grant none
  10. // @license MIT
  11. // @require https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.2.1/jquery.min.js
  12. // @require https://cdn.bootcss.com/moment.js/2.20.1/moment.min.js
  13. // @require https://greasyfork.org/scripts/404478-jsonexportexcel-min/code/JsonExportExcelmin.js?version=811266
  14. // @require https://greasyfork.org/scripts/455576-qmsg/code/Qmsg.js?version=1122361
  15. // ==/UserScript==
  16.  
  17. (function () {
  18. "use strict";
  19. var new_element = document.createElement("link");
  20. new_element.setAttribute("rel", "stylesheet");
  21. new_element.setAttribute("href", "https://qmsg.refrain.xyz/message.min.css");
  22. document.body.appendChild(new_element);
  23.  
  24. const button = document.createElement("div");
  25. button.textContent = "导出画像";
  26. Object.assign(button.style, {
  27. height: "34px",
  28. lineHeight: "var(--line-height, 34px)",
  29. alignItems: "center",
  30. color: "#FFF",
  31. background: "linear-gradient(60deg, rgb(95, 240, 225), rgb(47, 132, 254))",
  32. borderRadius: "5px",
  33. marginLeft: "10px",
  34. fontSize: "13px",
  35. padding: "0 10px",
  36. cursor: "pointer",
  37. fontWeight: "500"
  38. });
  39. button.addEventListener("click", urlClick);
  40.  
  41. //目标数据
  42. let target_data = null;
  43. let res_data = null;
  44.  
  45. (function listen() {
  46. var origin = {
  47. open: XMLHttpRequest.prototype.open,
  48. send: XMLHttpRequest.prototype.send,
  49. };
  50. XMLHttpRequest.prototype.open = function (a, b) {
  51. this.addEventListener("load", replaceFn);
  52. origin.open.apply(this, arguments);
  53. };
  54. XMLHttpRequest.prototype.send = function (a, b) {
  55. origin.send.apply(this, arguments);
  56. };
  57. function replaceFn(obj) {
  58. if (
  59. this?._url?.slice(0, 57) == "/product_node/v2/api/productAnalysis/productIndexPortrait"
  60. ) {
  61. target_data = JSON.parse(obj?.target?.response);
  62. res_data = JSON.parse(obj?.target?._data);
  63. }
  64. }
  65. })();
  66.  
  67. function getQueryVariable(variable) {
  68. var query = window.location.search.substring(1);
  69. var vars = query.split("&");
  70. for (var i = 0; i < vars.length; i++) {
  71. var pair = vars[i].split("=");
  72. if (pair[0] == variable) {
  73. return pair[1];
  74. }
  75. }
  76. return false;
  77. }
  78. const objData = {
  79. BRAND: '本品',
  80. COMPETITOR_BRAND: '对比商品',
  81. INDUSTRY_BRAND: '行业Top20',
  82. ALL: '全部',
  83. LIVE_ROOM: '直播',
  84. PRODUCT_CARD: '商品卡',
  85. SHORT_VIDEO: '短视频',
  86. PURCHASE: '商品购买',
  87. CLICK: '商品点击',
  88. CLICK_NOT_PURCHASE: '商品后未购',
  89. SHOW: '商品曝光',
  90. SHOW_NOT_PURCHASE: '曝光后未购',
  91. ADD_CART: '商品加购'
  92. }
  93.  
  94. //获取aadvid
  95. const aadvid = getQueryVariable("aadvid");
  96.  
  97. //message.js
  98. let loadingMsg = null;
  99.  
  100. function appendDoc() {
  101. const likeComment = document.querySelectorAll(".byted-radio-group-size-md")[3];
  102. if (likeComment) {
  103. likeComment.append(button);
  104. return;
  105. }
  106. setTimeout(appendDoc, 1000);
  107. }
  108. appendDoc();
  109.  
  110. function formatData(data) {
  111. const result = [];
  112. data.items.forEach((item) => {
  113. const newItem = {
  114. labelName: data.name,
  115. name: item.name,
  116. value: item.value,
  117. };
  118. result.push(newItem);
  119. });
  120. return result;
  121. }
  122.  
  123. async function getData(e) {
  124. loadingMsg = Qmsg.loading("正在导出,请勿重复点击!");
  125.  
  126. const formatRes = (res) => {
  127. return res?.map((v) => {
  128. return formatData(v);
  129. })
  130. .flat();
  131. };
  132. const targetRes_formatted = formatRes(e?.data?.competitorData);
  133. const contrastRes_formatted = formatRes(e?.data?.selfData);
  134.  
  135. const variables = res_data;
  136. expExcel([
  137. {
  138. label: `目标组A-${objData[variables.competitorDimension.benchmarkType]}-${objData[variables.competitorDimension.contentType]}-${objData[variables.competitorDimension.actionType]}`,
  139. value: targetRes_formatted,
  140. },
  141. {
  142. label: `目标组B-${objData[variables.selfDimension.benchmarkType]}-${objData[variables.selfDimension.contentType]}-${objData[variables.selfDimension.actionType]}`,
  143. value: contrastRes_formatted,
  144. },
  145. ]);
  146. }
  147.  
  148. function expExcel(e) {
  149. let contrast = {
  150. 标签类型: "labelName",
  151. 标签: "name",
  152. 占比: "value"
  153. };
  154. let fileName =
  155. document.querySelector(".byted-input-size-md").value || "data";
  156. let option = {};
  157. option.fileName = fileName; //文件名
  158. option.datas = e.map((v) => {
  159. return {
  160. sheetName: v.label,
  161. sheetData: v.value,
  162. sheetHeader: Object.keys(contrast),
  163. sheetFilter: Object.values(contrast),
  164. columnWidths: [], // 列宽
  165. };
  166. });
  167. var toExcel = new ExportJsonExcel(option);
  168. toExcel.saveExcel();
  169. setTimeout(() => {
  170. loadingMsg.close();
  171. }, 1000);
  172. }
  173.  
  174. function urlClick() {
  175. if (target_data) {
  176. loadingMsg = Qmsg.loading("正在导出,请勿重复点击!");
  177. getData(target_data);
  178. } else {
  179. loadingMsg = Qmsg.error("数据加载失败,请重试");
  180. }
  181. }
  182. })();
  183.  
  184.  
  185.