Greasy Fork

来自缓存

Greasy Fork is available in English.

亚马逊批量下载业务报告

垃圾亚马逊,连批量下载业务报告的方法都没有,只好自己写一个了

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         亚马逊批量下载业务报告
// @namespace    https://github.com/MaiXiaoMeng
// @version      0.0.8
// @description  垃圾亚马逊,连批量下载业务报告的方法都没有,只好自己写一个了
// @author       XiaoMeng Mai
// @license      GPLv3

// @match        https://*.amazon.com/*
// @match        https://*.amazon.co.uk/*
// @match        https://*.amazon.fr/*
// @match        https://*.amazon.it/*
// @match        https://*.amazon.es/*
// @match        https://*.amazon.co.jp/*
// @match        https://*.amazon.com.au/*
// @match        https://*.amazon.sg/*

// @grant        GM_info
// @grant        GM_xmlhttpRequest
// @grant        GM_getResourceText
// @grant        GM_download
// @grant        GM_addStyle
// @grant        GM_openInTab
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        unsafeWindow

// @compatible   firefox Tampermonkey
// @compatible   chrome Tampermonkey
// @compatible   edge Tampermonkey

// @require      https://unpkg.com/jquery
// @require      https://unpkg.com/moment
// @require      https://unpkg.com/sweetalert2

// @resource     element-plus    https://unpkg.com/element-plus/dist/index.css

// @note         0.0.8 [Amazon] 修复 业务报告 修复个别 日本站 不显示下载按钮的问题 
// @note         0.0.7 [Amazon] 新增 业务报告 支持按每天或者每月下载
// @note         0.0.6 [Amazon] 新增 业务报告 自动获取业务报告的全部字段
// @note         0.0.5 [Amazon] 新增 库存管理 显示库存管理产品的分类
// @note         0.0.4 [Amazon] 修复 业务报告 父商品详情页面销售和流量 和 详情页面销售和流量 错误显示批量下载按钮
// @note         0.0.3 [Amazon] 新增 业务报告 亚马逊企业购(B2B)相关数据列
// @note         0.0.2 [Amazon] 修复 业务报告 下载报告没有子ASIN列的问题
// @note         0.0.1 [Amazon] 新增 业务报告 详情页面销售和流量(按子商品)批量下载

// https://sweetalert2.github.io/
// https://element-plus.gitee.io/

// append() - 在被选元素的结尾插入内容(内容的结尾,比如说有个a标签,则是在</a>这个标签之前添加东西) <a>    [append]</a>
// prepend() - 在被选元素的开头插入内容(内容的开始,比如说有个a标签,则是在<a>这个标签之后添加东西) <a>[prepend]   </a>
// after() - 在被选元素之后插入内容(元素的结尾,比如说有个a标签,则是在</a>这个标签之后添加东西)    <a>    </a>[after]
// before() - 在被选元素之前插入内容(内容的开始,比如说有个a标签,则是在<a>这个标签之前添加东西)    [before]<a>    </a>

// waitForKeyElements('.entry-wrapper', 'xxxxx520.com', ['/'], false, false, (node, selector_txt, active_host, active_url) => {
//     if (GM_getValue('menu_amazon')) {
//         (async () => {
//             var response = await makeGetRequest(offcie365_url)
//             node.find('.xxx').append($(`<li><span><a target='_blank' href='${response.url}'">response</a></span></li>`))
//         })()
//     }
// })

// ==/UserScript==

var version_url = "http://greasyfork.icu/zh-CN/scripts/449460"

// 初始化脚本
initializationScript()
// [Amazon] 业务报告 | 详情页面销售和流量
waitForKeyElements('.css-1lafdix', '*', ['business-reports'], false, false, (node, selector_txt, active_host, active_url) => {
    if (GM_getValue('menu_amazon')) {
        if (node.attr('class').indexOf('business_report') == -1) {
            node.after($(`<div class="css-1lafdix business_report"><kat-button id='business_month' label="批量下载[月](.csv)" variant="primary" size="base" type="button"></kat-button></div> <div class="css-ix5zus"><kat-link label="" class="css-4g6ai3"></kat-link></div>`))
            node.after($(`<div class="css-1lafdix business_report"><kat-button id='business_day' label="批量下载[天](.csv)" variant="primary" size="base" type="button"></kat-button></div> <div class="css-ix5zus"><kat-link label="" class="css-4g6ai3"></kat-link></div>`))
            $(".business_report").click(function (event) {
                var legacy_report_id = $('.css-1qgr8dx').parent().attr('href').split('=')[1]
                var start_date = new Date($(".css-jfggi0")[0].value)
                var end_date = new Date($(".css-jfggi0")[1].value)
                var site_brand = $(".partner-dropdown-button > span").text().split(" | ");
                (async () => {
                    var api_url = `https://${document.domain}/business-reports/api`
                    var data = JSON.stringify({
                        operationName: "reportDataQuery",
                        variables: {
                            input: {
                                legacyReportId: legacy_report_id,
                            },
                        },
                        query: "query reportDataQuery($input: GetReportDataInput) {\n  getReportData(input: $input) {\n      columns {\n      label\n      translationKey\n      isDefaultSortAscending\n      isDefaultGraphed\n      isDefaultSelected\n      isDefaultSortColumn\n      __typename\n    }\n    rows\n    __typename\n  }\n}\n",
                    })

                    var response = await makeGetRequest(url = api_url, method = 'POST', data = data)
                    var columns = JSON.parse(response.responseText)['data']['getReportData']['columns']
                    var selected_columns = []
                    columns.forEach(element => { selected_columns.push(element['translationKey']) })

                    var download_date_list = []

                    if (event['target']['id'] == 'business_day') {
                        while (start_date <= end_date) {
                            var _start_date = moment(start_date).format('YYYY-MM-DD')
                            var _end_date = moment(start_date).format('YYYY-MM-DD')
                            download_date_list.push({ 'start_date': _start_date, 'end_date': _end_date })
                            start_date = new Date((start_date / 1000 + 86400 * 1) * 1000)
                        }
                    } else if (event['target']['id'] == 'business_month') {
                        while (start_date <= end_date) {
                            var _date = new Date(start_date)
                            var _date_label = true
                            var _start_date = moment(_date.setDate(1)).format('YYYY-MM-DD')
                            _date.setMonth(_date.getMonth() + 1)
                            var _end_date = moment(_date.setDate(0)).format('YYYY-MM-DD')

                            for (let index = 0; index < download_date_list.length; index++) {
                                const element = download_date_list[index]
                                if (_start_date == element['start_date']) {
                                    _date_label = false
                                    break
                                }
                            }

                            if (_date_label) download_date_list.push({ 'start_date': _start_date, 'end_date': _end_date })
                            start_date = new Date((start_date / 1000 + 86400 * 1) * 1000)
                        }
                    }

                    for (let index = 0; index < download_date_list.length; index++) {
                        const element = download_date_list[index]
                        var data = JSON.stringify({
                            operationName: "reportDataDownloadQuery",
                            variables: {
                                input: {
                                    legacyReportId: legacy_report_id,
                                    startDate: element['start_date'],
                                    endDate: element['end_date'],
                                    userSelectedRows: [],
                                    selectedColumns: selected_columns,
                                },
                            },
                            query: "query reportDataDownloadQuery($input: GetReportDataInput) {\n  getReportDataDownload(input: $input) {\n    url\n    __typename\n  }\n}\n",
                        })
                        var response = await makeGetRequest(url = api_url, method = 'POST', data = data)
                        var download_url = JSON.parse(response.responseText)["data"]["getReportDataDownload"]["url"]
                        var download_file_name = `${site_brand[1]}_${site_brand[0]}_${element['start_date']}.csv`
                        ElementPlus.ElMessage(`正在下载: ${download_file_name}`)
                        console.log(`正在下载: ${download_file_name} URL: ${download_url}`)
                        GM_download(download_url, download_file_name)
                    }
                })()
            })
        }
    }
})
// [Amazon] 管理库存 | 显示管理库存产品的分类
waitForKeyElements('.myi-sprite-container.myi-image > a', '*', ['inventory'], false, false, (node, selector_txt, active_host, active_url) => {
    var grab_node = node.attr('href').split('&')[2].replace('productType=', '');
    node.parent().after($(`<div><div><span style="color:#00F;font-size: initial;">${grab_node}</span></div>`))
})

// // Listing页面
// waitForKeyElements("#productTitle", getGigab2bProductInfo, ['/dp/', '/gp/'])
// waitForKeyElements("#ASIN", actionFunction, ['/dp/', '/gp/'])
// // 订单管理页面
// waitForKeyElements(".cell-body > .cell-body-title", getGigab2bTrackingNumber, ['orders-v3/']);
// waitForKeyElements(".a-spacing-mini > div > span.a-text-bold", getGigab2bTrackingNumber, ['orders-v3/'])
// waitForKeyElements(".myo-list-orders-product-name-cell> div:nth-child(3) > div", getGigab2bProductInfo, ['orders-v3/'])

// var flow_score_url = 'https://api.xiyouzhaoci.com/v1/flowScore/country/US/asin/'
// var word_counts_url = 'https://api.xiyouzhaoci.com/v1/wordCounts'
// var search_by_asin = 'https://api.xiyouzhaoci.com/v1/searchByAsin'

// GM_xmlhttpRequest({
//     url: flow_score_url + asin,
//     method: 'GET',
//     onload: function (response) {
//         console.log(response.responseText);
//     }
// })
// GM_xmlhttpRequest({
//     url: word_counts_url,
//     method: 'POST',
//     data: JSON.stringify({
//         'asin': `${asin}`,
//         'country': 'US',
//         'filters': [],
//         'query': '',
//         'rangeFilters': []
//     }),
//     onload: function (response) {
//         console.log(response.responseText);
//     }
// })
// GM_xmlhttpRequest({
//     url: search_by_asin,
//     method: 'POST',
//     data: JSON.stringify({
//         'asin': `${asin}`, 'country': 'US',
//         'page': 1,
//         'pageSize': 100,
//         'orders': [
//             {
//                 'field': 'follow',
//                 'order': 'desc'
//             }
//         ],
//         'filters': [],
//         'query': '',
//         'rangeFilters': []
//     }),
//     onload: function (response) {
//         console.log(response.responseText);
//     }
// })

/**
 * @description: 一个实用程序函数,用于 Greasemonkey 脚本, 检测和处理 AJAXed 内容
 * @param {*} selector_txt 元素选择器
 * @param {*} active_host 激活的域名
 * @param {*} active_url 激活的页面URL
 * @param {*} b_wait_once 是否只扫描一次
 * @param {*} iframe_selector 是否扫描Frame框架
 * @param {*} action_function 找到元素时运行的方法,传送 node, selector_txt, active_host, active_url 四个变量
 */
function waitForKeyElements(selector_txt, active_host, active_url, b_wait_once, iframe_selector, action_function) {
    if (active_host != '*' && document.domain.split('.').slice(-2).join('.') != active_host) return

    var active_url_type = false
    if (typeof active_url == "object") {
        for (let index = 0; index < active_url.length; index++) {
            if (window.location.href.indexOf(active_url[index]) > -1) {
                active_url_type = true
                break
            }
        }
    } else if (typeof active_url == "string") {
        if (window.location.href.indexOf(active_url) > -1) active_url_type = true
    }


    if (active_url_type) {
        var target_nodes, b_targets_found
        if (iframe_selector) {
            target_nodes = $(iframe_selector).contents().find(selector_txt)
        } else {
            target_nodes = $(selector_txt)
        }

        if (target_nodes && target_nodes.length > 0) {
            b_targets_found = true
            target_nodes.each(function () {
                var j_this = $(this)
                var already_found = j_this.data("alreadyFound") || false

                if (!already_found) {
                    logPrint(`selector_txt > ${selector_txt} active_host > ${active_host} active_url > ${active_url} b_wait_once > ${b_wait_once} iframe_selector > ${iframe_selector}`)
                    console.log(j_this);

                    var cancel_found = false
                    if (typeof action_function == "object") {
                        action_function.forEach(element => {
                            cancel_found = element(j_this, selector_txt, active_host, active_url);
                        })
                    } else if (typeof action_function == "function") {
                        cancel_found = action_function(j_this, selector_txt, active_url);
                    }

                    if (cancel_found) {
                        b_targets_found = false
                    } else {
                        j_this.data("alreadyFound", true);
                    }
                }
            })
        } else {
            b_targets_found = false;
        }

        var control_obj = waitForKeyElements.control_obj || {};
        var control_key = selector_txt.replace(/[^\w]/g, "_");
        var time_control = control_obj[control_key];

        if (b_targets_found && b_wait_once && time_control) {
            clearInterval(time_control);
            delete control_obj[control_key];
        } else {
            if (!time_control) {
                time_control = setInterval(function () {
                    waitForKeyElements(selector_txt, active_host, active_url, b_wait_once, iframe_selector, action_function);
                }, 300);
                control_obj[control_key] = time_control;
            }
        }
        waitForKeyElements.control_obj = control_obj;
    }
}
function makeGetRequest(url, method = 'GET', data = null) {
    logPrint(`${method} -> ${url}`)
    return new Promise((resolve, reject) => {
        GM_xmlhttpRequest({
            url: url,
            method: method,
            data: data,
            onload: function (response) {
                resolve(response);
            },
            onerror: function (error) {
                reject(error);
            }
        });
    });
}
function logPrint(params) {
    var date_time = $.trim(new Date(new Date().setHours(new Date().getHours() + 8)).toISOString().replace("Z", " ").replace("T", " "))
    var function_name = (new Error()).stack.split("\n")[2].trim().split(" ")[1]
    console.log(`[${date_time}][DEBUG] ${function_name} - ${params}`)
}
function sleep(interval) {
    return new Promise(resolve => { setTimeout(resolve, interval) })
}
function getGigab2bTrackingNumber(jNode, selectorTxt, activeURL) {
    var ERROR_ON_ORDER_NUMBER = "Upload Time refers to the time when the sales order is uploaded to the Marketplace.";
    var order_numbers = jNode.text();
    var query_order_url = "https://www.gigab2b.com/index.php?route=account/sales_order/sales_order_management/salesOrderList&filter_orderId=";

    GM_xmlhttpRequest({
        method: "GET",
        url: query_order_url + order_numbers,
        onload: function (response) {
            if (response.finalUrl.indexOf("account/login") > 0) {
                jNode.append($(`<a target='_blank' href='${query_order_url + order_numbers}'>&nbsp检测到未登录&nbsp</a>`))
            } else if (response.responseText.indexOf(ERROR_ON_ORDER_NUMBER) == -1) {
                jNode.append($(`<a target='_blank' href='${query_order_url + order_numbers}'>&nbsp订单号不存在&nbsp</a>`))
            } else {
                var response_text = $(response.responseText);

                if (window.location.href.indexOf("sellercentral.amazon.com") > 0) {
                    var tracking_numbers = response_text.find(".tracking-number > a");
                    var tracking_href = $.trim(
                        response_text.find(".tracking-number > a").attr("href")
                    );
                } else if (window.location.href.indexOf("sellercentral-japan.amazon.com") > 0) {
                    var tracking_numbers = response_text.find(".tracking-number > span");
                }

                if (tracking_numbers.length > 0) {
                    var tracking = $.trim(response_text.find(".tracking-number").prop("firstChild").nodeValue)
                    jNode.append($(`<a target='_blank' href='${tracking_href}'>&nbsp${tracking}&nbsp</a>`))
                    for (let index = 0; index < tracking_numbers.length; index++) {
                        jNode.append($(`<span>&nbsp${tracking_numbers[index].textContent}&nbsp</span>`))
                    }
                } else {
                    jNode.append($(`<a target='_blank' href='${query_order_url + order_numbers}'>&nbsp没有查询到物流追踪编号&nbsp</a>`))
                }
            }
        },
    });
}
function getGigab2bProductInfo(jNode, selectorTxt, activeURL) {
    var query_product_info_url = 'https://www.gigab2b.com/index.php?route=product/search&search='

    if (selectorTxt == '#productTitle') {
        (async () => {
            var sku = $.trim(jNode.text().match(/\(.*?, (.*?)\)/)[1])
            var response = await makeGetRequest(query_product_info_url + sku)
            var response_text = $(response.responseText);
            var product_url = response_text.find(".product-image > a").attr("href")

            if (typeof product_url == "undefined") product_url = query_product_info_url + sku
            logPrint(`product_url -> ${product_url}`)
            let result = $.trim(jNode.text()).replace(/(\(.*, .*\))/, `<a target='_blank' href='${product_url}'>$1</a>`)
            logPrint(`result -> ${result}`)
            jNode.empty()
            jNode.append(result)
        })()
    } else if (selectorTxt == '.myo-list-orders-product-name-cell> div:nth-child(3) > div') {
        (async () => {
            var sku = $.trim(jNode.text().replace('SKU:  ', ''))
            var response = await makeGetRequest(query_product_info_url + sku)
            var response_text = $(response.responseText);
            var product_url = response_text.find(".product-image > a").attr("href")
            if (typeof product_url == "undefined") product_url = query_product_info_url + sku
            logPrint(`product_url -> ${product_url}`)
            jNode.empty()
            jNode.append($(`<div><span>SKU</span>:  <a target='_blank' href='${product_url}'>${sku}</a></div>`))
        })()
    }
}
function initializationScript() {
    loadMenu()
    var $ = window.$
    var VueCDN = "https://lib.baomitu.com/vue/3.2.36/vue.global.prod.min.js"
    var ElementPlusCDN = "https://lib.baomitu.com/element-plus/2.2.2/index.full.min.js"
    GM_addStyle(GM_getResourceText("element-plus"))
    $.getScript(VueCDN, function () {
        console.log("[" + VueCDN + "] Vue 加载成功");
        $.getScript(ElementPlusCDN, function () {
            console.log("[" + ElementPlusCDN + "] ElementPlus 加载成功")
            var ElementPlus = unsafeWindow.ElementPlus;
            var Vue = unsafeWindow.Vue;
        })
    })
}
function loadMenu() {
    var menu_ALL = [
        ['menu_amazon', 'Amazon', 'Amazon', true],
    ], menu_ID = []

    // 如果读取到的值为 null 就写入默认值
    for (let i = 0; i < menu_ALL.length; i++) {
        if (GM_getValue(menu_ALL[i][0]) == null) { GM_setValue(menu_ALL[i][0], menu_ALL[i][3]) }
    }

    registerMenuCommand()

    // 注册脚本菜单
    function registerMenuCommand() {

        // 如果菜单ID数组多于菜单数组,说明不是首次添加菜单,需要卸载所有脚本菜单
        if (menu_ID.length > menu_ALL.length) {
            for (let i = 0; i < menu_ID.length; i++) {
                GM_unregisterMenuCommand(menu_ID[i])
            }
        }

        // 循环注册脚本菜单
        for (let i = 0; i < menu_ALL.length; i++) {
            menu_ALL[i][3] = GM_getValue(menu_ALL[i][0])
            menu_ID[i] = GM_registerMenuCommand(`${menu_ALL[i][3] ? '✅' : '❌'} ${menu_ALL[i][2]}`, function () {
                menu_switch(`${menu_ALL[i][0]}`, `${menu_ALL[i][1]}`, `${menu_ALL[i][2]}`, `${menu_ALL[i][3]}`)
            })
        }

        // 加入版本信息
        menu_ID[menu_ID.length] = GM_registerMenuCommand(`🏁 当前版本 ${GM_info['script']['version']}`, function () {
            window.GM_openInTab(version_url, { active: true, insert: true, setParent: true })
        })
    }

    //切换选项
    function menu_switch(name, ename, cname, value) {
        if (value == 'false') {
            console.log(name)
            // 重新注册脚本菜单,刷新网页
            GM_setValue(`${name}`, true)
            registerMenuCommand()
            location.reload()
            GM_notification({ text: `「${cname}」已开启\n`, timeout: 3500 })
        } else {
            console.log(name)
            // 重新注册脚本菜单,刷新网页
            GM_setValue(`${name}`, false)
            registerMenuCommand()
            location.reload()
            GM_notification({ text: `「${cname}」已关闭\n`, timeout: 3500 })
        }
        // 重新注册脚本菜单
        registerMenuCommand()
    }
}