Greasy Fork is available in English.

数银_全链路分析

数银扩展工具

// ==UserScript==
// @name         数银_全链路分析
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  数银扩展工具
// @author       siji-Xian
// @match        *://databank.tmall.com*
// @icon         https://www.google.com/s2/favicons?domain=oceanengine.com
// @grant        none
// @license      MIT
// @require      https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.2.1/jquery.min.js
// @require      https://cdn.bootcss.com/moment.js/2.20.1/moment.min.js
// @require      https://greasyfork.org/scripts/404478-jsonexportexcel-min/code/JsonExportExcelmin.js?version=811266
// @require      https://greasyfork.org/scripts/455576-qmsg/code/Qmsg.js?version=1122361
// ==/UserScript==

(function () {
  "use strict";
  if (
    location.href.startsWith(
      "https://databank.tmall.com/#/fullLinkDistribution"
    )
  ) {
    var new_element = document.createElement("link");
    new_element.setAttribute("rel", "stylesheet");
    new_element.setAttribute(
      "href",
      "https://qmsg.refrain.xyz/message.min.css"
    );

    const button = document.createElement("div");
    button.textContent = "导出数据";
    Object.assign(button.style, {
      height: "34px",
      lineHeight: "var(--line-height, 34px)",
      alignItems: "center",
      color: "white",
      background:
        "linear-gradient(90deg, rgba(0, 239, 253), rgba(64, 166, 254))",
      borderRadius: "5px",
      marginLeft: "10px",
      fontSize: "13px",
      padding: "0 10px",
      cursor: "pointer",
      fontWeight: "500",
    });
    button.addEventListener("click", urlClick);

    const button2 = document.createElement("div");
    button2.textContent = "创建WS连接";
    Object.assign(button2.style, {
      height: "34px",
      lineHeight: "var(--line-height, 34px)",
      alignItems: "center",
      color: "white",
      background:
        "linear-gradient(90deg, rgba(0, 239, 253), rgba(64, 166, 254))",
      borderRadius: "5px",
      marginLeft: "10px",
      fontSize: "13px",
      padding: "0 10px",
      cursor: "pointer",
      fontWeight: "500",
    });
    button2.addEventListener("click", wsClick);

    const getRequestOptions = {
      method: "GET",
      redirect: "follow",
    };

    async function fetchFun(url, data, requestOptions = getRequestOptions) {
      const params = new URLSearchParams(data).toString();
      try {
        const response = await fetch(`${url}?${params}`, requestOptions);
        if (response.ok) {
          const result = await response.json();
          return result;
        } else {
          throw new Error(`Fetch failed: ${response.status}`);
        }
      } catch (error) {
        loadingMsg.close();
        Qmsg.error({
          content: `网络请求错误: ${error.message}`,
          timeout: 5000,
        });
        throw error;
      }
    }

    function appendDoc() {
      const likeComment = document.querySelector(".databank-ceiling-bar");
      if (likeComment) {
        document.body.appendChild(new_element);
        likeComment.append(button2);
        likeComment.append(button);
        return;
      }
      setTimeout(appendDoc, 1000);
    }
    appendDoc();

    function getCrowdIdFromHash() {
      let url = new URL(window.location.href);
      let hash = url.hash;
      hash = hash.slice(23);
      let searchParams = new URLSearchParams(hash);
      let crowdId = searchParams.get("crowdId");
      return crowdId;
    }
    // 消息队列
    let tableList = [];
    let zongList = []

    //处理日期
    async function getDateRange(startDate, endDate) {
      const dateArray = [];
      const currentDate = moment(startDate);
      const lastDate = moment(endDate);

      while (currentDate <= lastDate) {
        dateArray.push(currentDate.format("YYYYMMDD"));
        currentDate.add(1, "days");
      }

      return dateArray;
    }
    let dates = [];

    async function getData(thedate) {
      const zong = await fetchFun(
        "https://databank.tmall.com/api/ecapi",
        {
          thedate,
          path: '/datatable/fulllink/'
        }
      );
      return zong?.data[1].uv
    }

    async function wsClick() {
      try {
        let res = prompt(
          "日期,例: 20230511,20230521 (起始页和结束页中间用英文逗号分隔)"
        );
        if (res) {
          let [startPage, endPage] = res.split(",");
          let startPageInt = parseInt(startPage);
          let endPageInt = parseInt(endPage);
          if (isNaN(startPageInt) || isNaN(endPageInt) || endPage < startPage) {
            throw new Error("日期格式错误!");
          }
          dates = await getDateRange(startPage, endPage);
        }
      } catch (err) {
        Qmsg.error(err.message);
      }
      // 调用函数获取 crowdId 的值
      tableList = [];

      // 获取总数值数据
      zongList = await Promise.all(dates.map(async v=>{
        return {key:v,value:await getData(v)}
      }))

      let data = {
        method: "/queryDataService/queryDataOnWidget",
        headers: { rid: "1694746656769012", type: "PULL" },
        body: {
          args: {
            referer: "databank-fullLinkDistribution",
            id: "892669",
            isMock: 0,
            whatIfParam: { widgetParamList: [], customParamList: [] },
            widgetSelections: null,
            selections: [
              {
                dimensionName: "cateId",
                restrictList: [{ hide: 1, oper: "eq", value: "-99" }],
                eq: [{ hide: 1, oper: "eq", value: "-99" }],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "-99",
              },
              {
                dimensionName: "brandId",
                restrictList: [{ hide: 1, oper: "eq", value: "3949661" }],
                eq: [{ hide: 1, oper: "eq", value: "3949661" }],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "3949661",
              },
              {
                dimensionName: "searchKeyword",
                restrictList: [{ hide: 1, oper: "eq", value: "" }],
                eq: [{ hide: 1, oper: "eq", value: "" }],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "",
              },
              {
                dimensionName: "buyRecency",
                restrictList: [
                  { hide: 1, oper: "eq", value: "1", showName: "<=1天" },
                ],
                eq: [{ hide: 1, oper: "eq", value: "1", showName: "<=1天" }],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "<=1天",
              },
              {
                dimensionName: "statusId",
                restrictList: [
                  { hide: 1, oper: "eq", value: "1020", showName: "兴趣" },
                ],
                eq: [{ hide: 1, oper: "eq", value: "1020", showName: "兴趣" }],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "兴趣",
              },
              {
                dimensionName: "theDate",
                restrictList: [{ hide: 1, oper: "eq", value: "20230914" }],
                eq: [{ hide: 1, oper: "eq", value: "20230914" }],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "20230914",
              },
              {
                dimensionName: "ds",
                restrictList: [
                  { hide: 1, oper: "le", value: "20230914" },
                  { hide: 1, oper: "ge", value: "undefined" },
                ],
                eq: null,
                lt: null,
                gt: null,
                ge: [{ hide: 1, oper: "ge", value: "undefined" }],
                le: [{ hide: 1, oper: "le", value: "20230914" }],
                ne: null,
                showText: "20230914, undefined",
              },
              {
                dimensionName: "isAll",
                restrictList: [{ hide: 1, oper: "eq", value: "1" }],
                eq: [{ hide: 1, oper: "eq", value: "1" }],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "1",
              },
              {
                dimensionName: "level1TouchId",
                restrictList: [
                  { hide: 1, oper: "eq", value: "8", showName: "付费广告" },
                ],
                eq: [{ hide: 1, oper: "eq", value: "8", showName: "付费广告" }],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "付费广告",
              },
              {
                dimensionName: "departmentType",
                restrictList: [
                  { hide: 1, oper: "eq", value: "EC", showName: "部门版本" },
                ],
                eq: [
                  { hide: 1, oper: "eq", value: "EC", showName: "部门版本" },
                ],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "部门版本",
              },
              {
                dimensionName: "commodityAnalysis",
                restrictList: [
                  { hide: 1, oper: "eq", value: "true", showName: "商品权限" },
                ],
                eq: [
                  { hide: 1, oper: "eq", value: "true", showName: "商品权限" },
                ],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "商品权限",
              },
              {
                dimensionName: "env",
                restrictList: [
                  { hide: 1, oper: "eq", value: "//databank.tmall.com" },
                ],
                eq: [{ hide: 1, oper: "eq", value: "//databank.tmall.com" }],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "//databank.tmall.com",
              },
              {
                dimensionName: "itemTag",
                restrictList: [
                  { hide: 1, showName: "全部", value: "-999", oper: "eq" },
                ],
                eq: [{ hide: 1, showName: "全部", value: "-999", oper: "eq" }],
                lt: null,
                gt: null,
                ge: null,
                le: null,
                ne: null,
                showText: "全部",
              },
            ],
            rdPathInfoList: [],
            appId: "6",
          },
        },
      };

      // 创建 WebSocket 连接
      const socket = new WebSocket("wss://ws-insight-engine.tmall.com/");

      // 监听连接成功事件
      socket.onopen = function (event) {
        console.log("WebSocket 连接已建立", new Date());
        Qmsg.info("WebSocket 连接已建立");
        // 在连接成功后发送消息
        dates.forEach((v) => {
          data.headers.rid = v;
          data.body.args.selections[5].restrictList[0].value = v;
          data.body.args.selections[5].eq[0].value = v;
          data.body.args.selections[5].showText = v;
          data.body.args.selections[6].restrictList[0].value = v;
          data.body.args.selections[6].le[0].value = v;

          socket.send(JSON.stringify(data));
        });
      };

      // 监听接收消息事件
      socket.onmessage = function (event) {
        let eventData = JSON.parse(event.data);
        if (eventData?.body?.axises.length==1 && eventData?.body?.datas.length==2 ) {
          tableList.push(eventData);
        }
      };

      // 监听连接关闭事件
      socket.onclose = function (event) {
        console.log("WebSocket 连接已关闭", new Date());
        // 在此处进行连接关闭后的处理
        Qmsg.info("WebSocket 连接已关闭");
      };

      // 监听发生错误事件
      socket.onerror = function (error) {
        console.error("WebSocket 发生错误:", error);
        // 在此处处理错误
        Qmsg.info("WebSocket 发生错误");
      };
    }

    //message.js
    let loadingMsg = null;

    function expExcel(e) {
      console.log(e)
      let mapData = new Map(
        e.map((item) => {
          let value = item.body.axises[0].values.map((v, i) => {
            return {
              key: v.showName,
              value: [
                item.body.datas[0].values[i],
                item.body.datas[1].values[i],
              ],
            };
          });
          return [item.headers.rid, value];
        })
      );
      let mapData2 = new Map(
        zongList.map((v) => {
          return [v.key,v.value]
        })
      )
      console.log(mapData2)

      let expData = dates.map((v) => {
        return {
          key: v,
          value: mapData2.get(v),
          value1: mapData.get(v)[0].value[0],
          value2: mapData.get(v)[0].value[1],
        };
      });

      let contrast = {
        日期: "key",
        num:'value',
        搜索占比: "value1",
        行业均值: "value2",
      };

      let option = {};
      option.fileName = "数银_全链路分析"; //文件名
      option.datas = [
        {
          sheetName: "",
          sheetData: expData,
          sheetHeader: Object.keys(contrast),
          sheetFilter: Object.values(contrast),
          columnWidths: [], // 列宽
        },
      ];

      var toExcel = new ExportJsonExcel(option);
      toExcel.saveExcel();
      loadingMsg.close();
    }

    function urlClick() {
      if (tableList.length) {
        loadingMsg = Qmsg.loading("正在导出,请勿重复点击!");
        expExcel(tableList);
      }else{
        Qmsg.warning("请先创建ws链接!");
      }

    }
  }
})();