亚马逊ABA数据自动下载

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

  1. // ==UserScript==
  2. // @name 亚马逊ABA数据自动下载
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.4.0
  5. // @description 通过JS脚本 实现亚马逊ABA数据 在季度、月、周的自动下载 此版本只包括了2024-12-23时期的年、季度、月、周数据 不排除在未来某些数据亚马逊不提供
  6. // @author You
  7. // @match https://sellercentral.amazon.co.uk/*
  8. // @match https://sellercentral.amazon.com/*
  9. // @match https://sellercentral.amazon.ca/*
  10. // @require https://scriptcat.org/lib/513/2.0.1/ElementGetter.js#sha256=V0EUYIfbOrr63nT8+W7BP1xEmWcumTLWu2PXFJHh5dg=
  11. // @icon data:image/gifbase64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  12. // @grant none
  13. // @license MIT
  14. // ==/UserScript==
  15. // 季度 > 月
  16. (function () {
  17. 'use strict';
  18. const timeRangeWeekStart = "2023-10-28"
  19. const config = {
  20. timeRange: ['quarterly', 'monthly', 'weekly', 'daily'],
  21. timeRangeYear: ['2024','2023'],
  22. timeRangeQuarter: ['03-31', '06-30', '09-30', '12-31'],
  23. 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'],
  24. timeRangeWeek: getSaturdaysUntilNow(timeRangeWeekStart),
  25. searchTerm: ['gloves', 'hair dryer']
  26. };
  27.  
  28. // 获取从指定开始日期到当前日期之间的所有周六日期
  29. function getSaturdaysUntilNow(startDate) {
  30. const saturdays = [];
  31. let currentDate = new Date(startDate);
  32. const now = new Date();
  33.  
  34. // 确保开始日期是周六
  35. while (currentDate.getDay() !== 6) {
  36. currentDate.setDate(currentDate.getDate() + 1);
  37. }
  38.  
  39. // 遍历从开始日期到当前日期之间的所有周六
  40. while (currentDate <= now) {
  41. saturdays.push(currentDate.toISOString().split('T')[0]);
  42. currentDate.setDate(currentDate.getDate() + 7);
  43. }
  44.  
  45. return saturdays;
  46. }
  47.  
  48. // 异步版 checkObj,返回 Promise
  49. function checkObjAsync(selector, timeInterval) {
  50. return new Promise((resolve, reject) => {
  51. const start = Date.now();
  52. // 设置超时时间 5 秒
  53. const timeout = 5000;
  54. let t = setInterval(() => {
  55. const targetElement = document.querySelector(selector);
  56. if (targetElement) {
  57. clearInterval(t);
  58. resolve(targetElement);
  59. } else if (Date.now() - start > timeout) {
  60. clearInterval(t);
  61. reject(new Error(`Timeout: Element not found for selector "${selector}"`));
  62. }
  63. }, timeInterval);
  64. });
  65. }
  66.  
  67. // 修改属性 & 触发事件
  68. function setAttrAndDispatchEv(obj, attr, value, eventType = "change") {
  69. obj.setAttribute(attr, value);
  70. obj.dispatchEvent(new Event(eventType, { bubbles: true }));
  71. }
  72.  
  73. // 模拟点击事件
  74. async function clickEvent() {
  75. try {
  76. // search await——同步执行
  77. const obj1 = await checkObjAsync(".css-1oy4rvw", 1000);
  78. // obj1.setAttribute("label", "点击1-应用");
  79. setTimeout(() => {
  80. obj1.dispatchEvent(new Event("click", { bubbles: true, cancelable: false }));
  81. }, 1000);
  82.  
  83. // download-1 & download-2
  84. const downloadButtons = [
  85. ".css-1bvc4cc #GenerateDownloadButton",
  86. ".css-ivrut9 .css-ja60r3 .css-1nln1ln"
  87. ];
  88. for (const selector of downloadButtons) {
  89. const obj = await checkObjAsync(selector, 1000);
  90. // error
  91. if (selector === ".css-ivrut9 .css-ja60r3 .css-1nln1ln") {
  92. const label = obj.getAttribute("label");
  93. if (label === "请重试") {
  94. alert("Label is '请重试', waiting for 10 minutes...");
  95. await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // Wait 10 minutes
  96. }
  97. }
  98. // download click
  99. setTimeout(() => {
  100. obj.dispatchEvent(new Event("click", { bubbles: true, cancelable: false }));
  101. }, 1000);
  102. }
  103.  
  104. // close dialog
  105. const closeObj = await checkObjAsync(".css-ivrut9 .css-ja60r3 kat-button", 1000);
  106. setTimeout(() => {
  107. closeObj.dispatchEvent(new Event("click", { bubbles: true, cancelable: false }));
  108. }, 2000);
  109. } catch (error) {
  110. console.error("Error in clickEvent:", error.message);
  111. }
  112. }
  113.  
  114. // 处理年份、月份、每周
  115. async function processYearsAndTimeRanges(yearsOrWeeks, timeRanges, timeRangeType, yearOrWeekSelector) {
  116. try {
  117. const timeRangeObj = await checkObjAsync(".css-cyf03k #reporting-range", 1000);
  118. // timeRangeType
  119. setAttrAndDispatchEv(timeRangeObj, 'value', timeRangeType);
  120.  
  121. if (timeRanges) {
  122. for (const year of yearsOrWeeks) {
  123. // 这个也需要修改 #quarterly-year
  124. const yearObj = await checkObjAsync(yearOrWeekSelector, 1000);
  125.  
  126. setAttrAndDispatchEv(yearObj, 'value', year);
  127.  
  128. for (const timeRange of timeRanges) {
  129. const timeRangeValue = `${year}-${timeRange}`;
  130. // alert(timeRangeValue);
  131.  
  132. const timeRangeSelector = ".css-owk1mx .css-cyf03k .css-xccmpe";
  133. const timeRangeObj = await checkObjAsync(timeRangeSelector, 1000);
  134. setAttrAndDispatchEv(timeRangeObj, 'value', timeRangeValue);
  135.  
  136. // 每次循环独立执行 clickEvent
  137. await clickEvent();
  138. }
  139. }
  140. } else {
  141. // weekly不需要year、quarter、month筛选
  142. for (const week of yearsOrWeeks) {
  143. const weekObj = await checkObjAsync(yearOrWeekSelector, 1000);
  144. setAttrAndDispatchEv(weekObj, 'value', week);
  145. // 每次循环独立执行 clickEvent
  146. await clickEvent();
  147. }
  148. }
  149.  
  150. } catch (error) {
  151. console.error("Error in processYearsAndMouths:", error.message);
  152. }
  153. }
  154.  
  155. // 跳转至下载管理器
  156. function navigateToDownloadManager() {
  157. const currentUrl = window.location.href;
  158. const targetSubstring = "brand-analytics/dashboard/";
  159. if (currentUrl.includes(targetSubstring)) {
  160. window.open("/brand-analytics/download-manager", "_blank");
  161. console.log("已跳转到下载管理器");
  162. } else {
  163. console.log("当前页面不包含下载管理器链接,跳过跳转");
  164. }
  165. }
  166.  
  167. // 下载页面 循环下载
  168. async function handleDownloadABA() {
  169. // 获取父元素
  170. const rowGroup = await checkObjAsync('div[role="rowgroup"]', 1000);
  171.  
  172. if (!rowGroup) {
  173. console.error("未找到 role='rowgroup' 的父元素");
  174. return;
  175. }
  176.  
  177. // 获取所有子元素 role="row"
  178. const rows = rowGroup.querySelectorAll('div[role="row"]');
  179. if (rows.length === 0) {
  180. console.error("未找到 role='row' 的子元素");
  181. return;
  182. }
  183.  
  184. // 定义一个异步函数处理单个点击
  185. const clickRow = async (row) => {
  186. // 查找 class="css-p1ypz0" 的 div
  187. const actionDiv = row.querySelector('.css-p1ypz0');
  188. if (actionDiv) {
  189. // 查找 <span> 标签
  190. const downloadSpan = actionDiv.querySelector('span.css-1mwk1ex');
  191. if (downloadSpan) {
  192. // 模拟点击
  193. downloadSpan.click();
  194. console.log(`已点击下载按钮:`, downloadSpan);
  195. // 模拟等待,避免过快操作(根据需要调整时间)
  196. await new Promise(resolve => setTimeout(resolve, 500));
  197. } else {
  198. console.warn(`未找到下载按钮 span 标签于:`, row);
  199. }
  200. } else {
  201. console.warn(`未找到 class="css-p1ypz0" div 于:`, row);
  202. }
  203. };
  204.  
  205. // 按顺序遍历并执行点击操作
  206. for (const row of rows) {
  207. await clickRow(row);
  208. }
  209.  
  210. console.log("所有下载按钮已按顺序点击完成");
  211. }
  212.  
  213. // 主执行逻辑
  214. async function main() {
  215. // 处理季度
  216. // await processYearsAndTimeRanges(
  217. // config.timeRangeYear,
  218. // config.timeRangeQuarter,
  219. // config.timeRange[0],
  220. // ".css-cyf03k #quarterly-year"
  221. // );
  222.  
  223.  
  224. // 处理月份
  225. // await processYearsAndTimeRanges(
  226. // config.timeRangeYear,
  227. // config.timeRangeMonth,
  228. // config.timeRange[1],
  229. // ".css-cyf03k #monthly-year"
  230. // );
  231.  
  232. // 处理每周
  233. await processYearsAndTimeRanges(
  234. config.timeRangeWeek,
  235. 0,
  236. config.timeRange[2],
  237. ".css-cyf03k #weekly-week"
  238. );
  239. // 跳转至下载管理器
  240. // navigateToDownloadManager()
  241. // await handleDownloadABA()
  242. }
  243. main();
  244.  
  245. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址