Greasy Fork

Greasy Fork is available in English.

美团商家流量导出Excel

增加了流量来源

当前为 2021-01-07 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         美团商家流量导出Excel
// @namespace    http://tampermonkey.net/
// @version      0.1.5
// @description  增加了流量来源
// @author       yhpl-pgq
// @match        https://shangoue.meituan.com/*
// @require      http://cdn.staticfile.org/xlsx/0.16.1/xlsx.mini.min.js
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
    'use strict';
    addButton();
    console.log('enter')
})();
var xmlExportContent = {traffic:[], source:[]};
var yhplHTTPCount = 0;
function addButton(){
    var headerLeft = $("#reload-page")[0];
    var header = headerLeft.parentElement;
    var button = document.createElement('BUTTON');
    button.innerText = "我是小可爱";
    button.onclick = getStore;
    button.id = "yhplExport";
    header.appendChild(button);
}
function onStoreSuccess(node){
    var code = node.code
    window.node = node;
    console.log('onSuccess, code:'+code);
    if (code == 0){
        var data = node.data;
        var length = data.length;
        var totalRequestSize = length * 2;
        length = 2;
        totalRequestSize = length * 2;
        for(var poi = 0; poi < length; poi++){
            var child = data[poi];
            console.log(child.poiName+"," +child.id);
            // if (poi < 3){
            getStoreDetail(poi * 2, totalRequestSize, child.id, child.poiName);
            getStoreTrafficSource(poi * 2 + 1, totalRequestSize, child.id, child.poiName);
            //}
            yhplSleep();
        }

    }
}
async function yhplSleep() {
  console.log('Hello')
  await sleep(200)
  console.log('world!')
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}


function onStoreError(e){
    console.log(e);
    console.log('onError');
}
function getStore(){
    yhplHTTPCount = 0;
    xmlExportContent = {traffic:[], source:[]};
    xmlExportContent.traffic.push(['店铺名字', '指标名称', '当前', '7日对比', '行业对比'])
    xmlExportContent.source.push(['店铺名字', '指标名称','曝光人数', '搜索', '商家列表', '订单页', '其他', '活动专区', '为你优选'])
    console.log('req user');
    var URL_STORE = 'https://shangoue.meituan.com/api/poi/poiList';
    $.ajax({
        type: "POST",
        url: URL_STORE,
        data: '',
        success: onStoreSuccess,
        error:onStoreError,
        dataType: 'json'
    });
}
function onStoreDetailSuccess(step, total, text, storeID, storeName){
    console.log('onStoreDetailSuccess:'+step);
    var node = JSON.parse(text);
    var code = node.code
    console.log('onSuccess, code:'+code+",step:"+step);
    if (code == 0){
        var data = node.data;
        var storeDetailRows = [];
        if (data != null) {
            var length = data.length;
            for(var index = 0; index < length; index++){
                var child = data[index];
                var indexStr = child.index;
                var indexParsed = acceptDataNode(indexStr);
                var indexInt = getTrafficIndexAsInt(indexStr);
                if (indexParsed.length > 0 && indexInt >= 0){
                    var current = child.current;
                    var ring = child.ring;
                    var peer= child.peer;
                    if (peer== null && ring == null && peer == null) {
                        continue;
                    }
                    var storeDetailRow = [];
                    storeDetailRow.push(getStoreName(storeName, storeID));
                    storeDetailRow.push(indexParsed);
                    storeDetailRow.push(appendDateSuffix(indexStr, current));
                    storeDetailRow.push(appendDateSuffix(indexStr, ring));
                    storeDetailRow.push(appendDateSuffix(indexStr, peer));
                    storeDetailRows[indexInt] = storeDetailRow;
                    // console.log(child.index+"," +child.current);
                }
            }
            var rows = storeDetailRows.length;
            for(var rowIndex = 0; rowIndex < rows; rowIndex++){
                var row = storeDetailRows[rowIndex];
                if(row == null){
                    continue;
                }
                xmlExportContent.traffic.push(row);
            }
        } else {
            console.log('数据获取失败:'+storeID);
        }
    } else {
        console.log('数据获取失败:'+storeID+",code:"+code);
    }
   showProgress(step, total);
}
function getStoreName(storeName, storeID){
    if (storeID > 0){
        return (storeName+"("+storeID+")");
    } else {
        return storeName;
    }
}
function onStoreTrafficSourceSuccess(step, total, text, storeID, storeName){
    var node = JSON.parse(text);
    var code = node.code

    //console.log('onSuccess, code:'+code);
    if (code != 0) {
        console.log('流量来源数据获取失败#1:'+storeID);
        showProgress(step, total);
        return;
    }
    var data = node.data;
    if(data == null) {
        console.log('流量来源数据获取失败#2:'+storeID+",step:"+step);
        showProgress(step, total);
        return;
    }
    var detail = data.detail;
    if (detail == null) {
        console.log('流量来源数据获取失败#3:'+storeID);
        showProgress(step, total);
        return;
    }
    var storeTrafficSourceRows = ['未知', '曝光来源', 0, 0, 0, 0, 0, 0, 0];
    storeTrafficSourceRows[0] = getStoreName(storeName, storeID);
    storeTrafficSourceRows[2] = data.current;
    var length = detail.length;
    for(var index = 0; index < length; index++){
        var child = detail[index];
        var indexStr = child.index;
        var indexParsed = getIndexAsInt(indexStr);
        if (indexParsed>=0){
            storeTrafficSourceRows[indexParsed + 3] = child.current;
        }
    }
    xmlExportContent.source.push(storeTrafficSourceRows);
    showProgress(step, total);
}


function appendDateSuffix(index, val){
    if (val == null){
        return "";
    }
    if (index.indexOf('RATE')>=0){
        val = val + "%";
    }
    return val;
}

function acceptDataNode(index) {
    switch (index){
        case "FLOW_POI_EXPOSE_UV":
            return "曝光人数";
        case "FLOW_POI_EXPOSE_PV":
            return "曝光次数";
        case "FLOW_WEIGHTED_AVG_RANKING":
            return "平均排名";
        case "FLOW_HOME_PAGE_EXPOSE_RATE":
            return "入店转化率";
        case "FLOW_HOME_PAGE_UV":
            return "入店人数";
        case "FLOW_HOME_PAGE_PV":
            return "入店次数";
        case "FLOW_HOME_PAGE_DURATION":
            return "入店访问时长";
        case "FLOW_SUBMITTED_HOME_PAGE_RATE":
            return "下单转化率";
        case "FLOW_SUBMITTED_UV":
            return "下单人数";
        case "FLOW_SUBMITTED_PV":
            return "下单次数";
        case "FLOW_SUBMITTED_ACTUAL_AMT":
            return "下单金额";
        case "FLOW_PAY_UV":
            return "支付人数";
        case "FLOW_PAY_ACTUAL_AMT":
            return "支付金额";
        case "FLOW_PAY_SUBMITTED_RATE":
            return "支付转化率";
        default:
            return index;
    }
}

function getTrafficIndexAsInt(index) {
    switch (index){
        case "FLOW_POI_EXPOSE_UV":
            return 0;
        case "FLOW_POI_EXPOSE_PV":
            return 1;
        case "FLOW_WEIGHTED_AVG_RANKING":
            return 2;
        case "FLOW_HOME_PAGE_EXPOSE_RATE":
            return 3;
        case "FLOW_HOME_PAGE_UV":
            return 4;
        case "FLOW_HOME_PAGE_PV":
            return 5;
        case "FLOW_HOME_PAGE_DURATION":
            return 6;
        case "FLOW_SUBMITTED_HOME_PAGE_RATE":
            return 7;
        case "FLOW_SUBMITTED_UV":
            return 8;
        case "FLOW_SUBMITTED_PV":
            return 9;
        case "FLOW_SUBMITTED_ACTUAL_AMT":
            return 10;
        case "FLOW_PAY_UV":
            return 11;
        case "FLOW_PAY_ACTUAL_AMT":
            return 12;
        case "FLOW_PAY_SUBMITTED_RATE":
            return 13;
        default:
            return -1;
    }
}
function getIndexAsInt(index){
    switch (index){
        case "FLOW_SOURCE_FROM_SEARCH":
            return 0;
        case "FLOW_SOURCE_FROM_POI_LIST":
            return 1;
        case "FLOW_SOURCE_FROM_ORDER_PAGE":
            return 2;
        case "FLOW_SOURCE_FROM_OTHER":
            return 3;
        case "FLOW_SOURCE_FROM_ACT_AREA":
            return 4;
        case "FLOW_SOURCE_FROM_SELECTED":
            return 5;
        default:
            return -1;
    }
}


function getStoreDetail(index, total, storeID, storeName){
    var URL_PREFIX = 'https://waimaieapp.meituan.com/igate/recoanalysis/flowAnalysisV4/recentDays/flowTransformation?acctId=69808847&source=0&recentDays=7';
    var storeParmas = '&cityIds=0&wmPoiId='+storeID;
    var URL_DETAIL = URL_PREFIX + storeParmas
    GM_xmlhttpRequest({
        method: "GET",
        url: URL_DETAIL,
        data: '',
        headers:  {
            "Referer": "https://waimaieapp.meituan.com/igate/",
            "Content-Type": "application/x-www-form-urlencoded"
        },
        onload: function(res){
            console.log('getStoreDetail:'+index);
//            console.log('getStoreDetail:'+res.status);
            if(res.status === 200){
                //  console.log('成功')
                //console.log(res);
  //              console.log('getStoreDetail:onStoreDetailSuccess');
                onStoreDetailSuccess(index, total, res.response, storeID, storeName);
            }else{
                console.log('失败')
                //console.log(res)
            }
        },
        onerror : function(err){
            console.log('error')
            console.log(err)
        }
    });
}

function getStoreTrafficSource(index, total, storeID, storeName){
    var URL_PREFIX = 'https://waimaieapp.meituan.com/igate/recoanalysis/flowAnalysisV4/recentDays/flowTrafficSource?acctId=69808847&source=0&recentDays=7';
    var storeParmas = '&cityIds=0&wmPoiId='+storeID;
    var URL_DETAIL = URL_PREFIX + storeParmas
    GM_xmlhttpRequest({
        method: "GET",
        url: URL_DETAIL,
        data: '',
        headers:  {
            "Referer": "https://waimaieapp.meituan.com/igate/",
            "Content-Type": "application/x-www-form-urlencoded"
        },
        onload: function(res){
            if(res.status === 200){
                onStoreTrafficSourceSuccess(index, total, res.response, storeID, storeName);
            }else{
                console.log(res)
            }
        },
        onerror : function(err){
            console.log('error')
            console.log(err)
        }
    });
}
function showProgress(step, total){
    yhplHTTPCount = yhplHTTPCount + 1;
    console.log('total:'+yhplHTTPCount+", index:"+step);
    var button = $("#yhplExport")[0];
    button.innerText = "导出进度:"+yhplHTTPCount + "/ "+total;
//    console.log(xmlExportContent);
    if (yhplHTTPCount >= total){
        button.innerText = "下载Excel";
        exportAsXLS(xmlExportContent);
    }
}

//segment excel
function exportAsXLS(table){
    var excelName = "流量分析.xlsx";
    var sheet = XLSX.utils.aoa_to_sheet(table.traffic);
    var source = XLSX.utils.aoa_to_sheet(table.source);
    openDownloadDialog(sheet2blob([{sheet: sheet,name:'流量分析'},{sheet: source,name:'流量来源'}]),excelName);
}
function sheet2blob(sheets) {
    var sheetsSize = sheets.length;
    var SheetNames = [];
    var Sheets = {};
    for (var index = 0; index<sheets.length; index++){
        var child = sheets[index];
        var sheetName = child.name || 'sheet'+(index+1);
        SheetNames.push(sheetName);
        var sheet = child.sheet;
        Sheets[sheetName] = sheet;
    }

    var workbook = {
        SheetNames: SheetNames,
        //Sheets: {}
        Sheets: Sheets
    };
    //workbook.Sheets[sheetName] = sheet; // 生成excel的配置项

    var wopts = {
        bookType: 'xlsx', // 要生成的文件类型
        bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
        type: 'binary'
    };
    var wbout = XLSX.write(workbook, wopts);
    var blob = new Blob([s2ab(wbout)], {
        type: "application/octet-stream"
    }); // 字符串转ArrayBuffer
    function s2ab(s) {
        var buf = new ArrayBuffer(s.length);
        var view = new Uint8Array(buf);
        for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
        return buf;
    }
    return blob;
}
function openDownloadDialog(url, saveName) {
    if (typeof url == 'object' && url instanceof Blob) {
        url = URL.createObjectURL(url); // 创建blob地址
    }
    var aLink = document.createElement('a');
    aLink.href = url;
    aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
    var event;
    if (window.MouseEvent) event = new MouseEvent('click');
    else {
        event = document.createEvent('MouseEvents');
        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    }
    aLink.dispatchEvent(event);
}
//eng segment excel