Greasy Fork

Greasy Fork is available in English.

亚马逊ABA数据自动下载

通过JS脚本 实现亚马逊ABA数据 在季度、月、周的自动下载 此版本只包括了2024-12-23时期的年、季度、月、周数据 不排除在未来某些数据亚马逊不提供

目前为 2024-12-27 提交的版本,查看 最新版本

// ==UserScript==
// @name         亚马逊ABA数据自动下载
// @namespace    http://tampermonkey.net/
// @version      1.3.0
// @description  通过JS脚本 实现亚马逊ABA数据 在季度、月、周的自动下载   此版本只包括了2024-12-23时期的年、季度、月、周数据 不排除在未来某些数据亚马逊不提供
// @author       You
// @match        https://sellercentral.amazon.co.uk/*
// @match        https://sellercentral.amazon.com/*
// @match        https://sellercentral.amazon.ca/*
// @require      https://scriptcat.org/lib/513/2.0.1/ElementGetter.js#sha256=V0EUYIfbOrr63nT8+W7BP1xEmWcumTLWu2PXFJHh5dg=
// @icon         data:image/gifbase64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @license      MIT
// ==/UserScript==
// 季度 > 月
(function () {
    'use strict';

    const config = {
        timeRange: ['quarterly', 'monthly', 'weekly', 'daily'],
        timeRangeYear: ['2024', '2023'],
        timeRangeQuarter: ['03-31', '06-30', '09-30', '12-31'],
        timeRangeMonth: ['01-31', '02-28', '02-29', '03-31', '04-30', '05-31', '06-30', '07-31', '08-31', '09-30', '10-31', '11-30', '12-31'],
        timeRangeWeek: [
            "2023-10-21", "2023-10-28", "2023-11-04", "2023-11-11", "2023-11-18", "2023-11-25",
            "2023-12-02", "2023-12-09", "2023-12-16", "2023-12-23", "2023-12-30",
            "2024-01-06", "2024-01-13", "2024-01-20", "2024-01-27", "2024-02-03", "2024-02-10",
            "2024-02-17", "2024-02-24", "2024-03-02", "2024-03-09", "2024-03-16", "2024-03-23",
            "2024-03-30", "2024-04-06", "2024-04-13", "2024-04-20", "2024-04-27", "2024-05-04",
            "2024-05-11", "2024-05-18", "2024-05-25", "2024-06-01", "2024-06-08", "2024-06-15",
            "2024-06-22", "2024-06-29", "2024-07-06", "2024-07-13", "2024-07-20", "2024-07-27",
            "2024-08-03", "2024-08-10", "2024-08-17", "2024-08-24", "2024-08-31", "2024-09-07",
            "2024-09-14", "2024-09-21", "2024-09-28", "2024-10-05", "2024-10-12", "2024-10-19",
            "2024-10-26", "2024-11-02", "2024-11-09", "2024-11-16", "2024-11-23", "2024-11-30",
            "2024-12-07"
        ],
        searchTerm: ['gloves', 'hair dryer']
    };

    // 异步版 checkObj,返回 Promise
    function checkObjAsync(selector, timeInterval) {
        return new Promise((resolve, reject) => {
            const start = Date.now();
            // 设置超时时间 5 秒
            const timeout = 5000;
            let t = setInterval(() => {
                const targetElement = document.querySelector(selector);
                if (targetElement) {
                    clearInterval(t);
                    resolve(targetElement);
                } else if (Date.now() - start > timeout) {
                    clearInterval(t);
                    reject(new Error(`Timeout: Element not found for selector "${selector}"`));
                }
            }, timeInterval);
        });
    }

    // 修改属性 & 触发事件
    function setAttrAndDispatchEv(obj, attr, value, eventType = "change") {
        obj.setAttribute(attr, value);
        obj.dispatchEvent(new Event(eventType, { bubbles: true }));
    }

    // 模拟点击事件
    async function clickEvent() {
        try {
            // search await——同步执行
            const obj1 = await checkObjAsync(".css-1oy4rvw", 1000);
            // obj1.setAttribute("label", "点击1-应用");
            setTimeout(() => {
                obj1.dispatchEvent(new Event("click", { bubbles: true, cancelable: false }));
            }, 1000);

            // download-1 & download-2
            const downloadButtons = [
                ".css-1bvc4cc #GenerateDownloadButton",
                ".css-ivrut9 .css-ja60r3 .css-1nln1ln"
            ];
            for (const selector of downloadButtons) {
                const obj = await checkObjAsync(selector, 1000);
                // download click
                setTimeout(() => {
                    obj.dispatchEvent(new Event("click", { bubbles: true, cancelable: false }));
                }, 1000);
            }

            // close dialog
            const closeObj = await checkObjAsync(".css-ivrut9 .css-ja60r3 kat-button", 1000);
            setTimeout(() => {
                closeObj.dispatchEvent(new Event("click", { bubbles: true, cancelable: false }));
            }, 2000);
        } catch (error) {
            console.error("Error in clickEvent:", error.message);
        }
    }

    // 处理年份、月份、每周
    async function processYearsAndTimeRanges(yearsOrWeeks, timeRanges, timeRangeType, yearOrWeekSelector) {
        try {
            const timeRangeObj = await checkObjAsync(".css-cyf03k #reporting-range", 1000);
            // timeRangeType
            setAttrAndDispatchEv(timeRangeObj, 'value', timeRangeType);

            if (timeRanges) {
                for (const year of yearsOrWeeks) {
                    // 这个也需要修改 #quarterly-year
                    const yearObj = await checkObjAsync(yearOrWeekSelector, 1000);

                    setAttrAndDispatchEv(yearObj, 'value', year);

                    for (const timeRange of timeRanges) {
                        const timeRangeValue = `${year}-${timeRange}`;
                        alert(timeRangeValue);

                        const timeRangeSelector = ".css-owk1mx .css-cyf03k .css-xccmpe";
                        const timeRangeObj = await checkObjAsync(timeRangeSelector, 1000);
                        setAttrAndDispatchEv(timeRangeObj, 'value', timeRangeValue);

                        // 每次循环独立执行 clickEvent
                        await clickEvent();
                    }
                }
            } else {
                // weekly不需要year、quarter、month筛选
                for (const week of yearsOrWeeks) {
                    const weekObj = await checkObjAsync(yearOrWeekSelector, 1000);

                    setAttrAndDispatchEv(weekObj, 'value', week);
                }
            }

        } catch (error) {
            console.error("Error in processYearsAndMouths:", error.message);
        }
    }

    // 跳转至下载管理器
    function navigateToDownloadManager() {
        const currentUrl = window.location.href;
        const targetSubstring = "brand-analytics/dashboard/";
        if (currentUrl.includes(targetSubstring)) {
            window.open("/brand-analytics/download-manager", "_blank");
            console.log("已跳转到下载管理器");
        } else {
            console.log("当前页面不包含下载管理器链接,跳过跳转");
        }
    }

    // 下载页面 循环下载
    async function handleDownloadABA() {
        const rowGroup = await checkObjAsync('div[role="rowgroup"]', 1000);

        if (!rowGroup) {
            console.error("未找到 role='rowgroup' 的父元素");
            return;
        }

        // role="row"
        const rows = rowGroup.querySelectorAll('div[role="row"]');
        if (rows.length === 0) {
            console.error("未找到 role='row' 的子元素");
            return;
        }

        // 定义一个异步函数处理单个点击
        const clickRow = async (row) => {
            // 查找 class="css-p1ypz0" 的 div
            const actionDiv = row.querySelector('.css-p1ypz0');
            if (actionDiv) {
                const downloadSpan = actionDiv.querySelector('span.css-1mwk1ex');
                if (downloadSpan) {
                    downloadSpan.click();
                    console.log(`已点击下载按钮:`, downloadSpan);
                    // 延时 防止过快
                    await new Promise(resolve => setTimeout(resolve, 500));
                } else {
                    console.warn(`未找到下载按钮 span 标签于:`, row);
                }
            } else {
                console.warn(`未找到 class="css-p1ypz0" 的 div 于:`, row);
            }
        };

        //forof+await保持同步
        for (const row of rows) {
            await clickRow(row);
        }

        console.log("所有下载按钮已按顺序点击完成");
    }

    // 主执行逻辑
    async function main() {
        // 处理季度
        await processYearsAndTimeRanges(
            config.timeRangeYear,
            config.timeRangeQuarter,
            config.timeRange[0],
            ".css-cyf03k #quarterly-year"
        );

        // 处理月份
        await processYearsAndTimeRanges(
            config.timeRangeYear,
            config.timeRangeMonth,
            config.timeRange[1],
            ".css-cyf03k #monthly-year"
        );

        // 处理每周
        await processYearsAndTimeRanges(
            config.timeRangeWeek,
            0,
            config.timeRange[2],
            ".css-cyf03k #weekly-week"
        );

        // 跳转至下载管理器
        navigateToDownloadManager()

        await handleDownloadABA()
    }

    main();

})();