// ==UserScript== // @name EPIC游戏库存导出 // @namespace http://tampermonkey.net/ // @version 1.4 // @license PaperTiger // @description 精确提取EPIC游戏订单信息,基于HTML表格结构,包括付款金额、游戏名称、订单日期等。 // @author Paper Tiger // @match *://*.epicgames.com/account/* // @require https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.17.0/xlsx.full.min.js // @grant none // @downloadURL none // ==/UserScript== /* global XLSX */ (function() { 'use strict'; let isProcessing = false; let currentPage = 0; let allOrderData = []; function createExportButton() { const button = document.createElement('button'); button.textContent = '开始导出'; button.id = 'epic-export-btn'; button.style.position = 'fixed'; button.style.top = '10px'; button.style.right = '400px'; button.style.zIndex = '99999'; button.style.padding = '10px'; button.style.backgroundColor = 'rgba(40, 167, 69, 1)'; button.style.color = 'white'; button.style.border = '2px solid red'; button.style.borderRadius = '5px'; button.style.cursor = 'pointer'; document.body.appendChild(button); // 创建进度显示区域 const progressDiv = document.createElement('div'); progressDiv.id = 'epic-progress'; progressDiv.style.position = 'fixed'; progressDiv.style.top = '50px'; progressDiv.style.right = '400px'; progressDiv.style.zIndex = '99999'; progressDiv.style.padding = '10px'; progressDiv.style.backgroundColor = 'rgba(0, 0, 0, 0.8)'; progressDiv.style.color = 'white'; progressDiv.style.borderRadius = '5px'; progressDiv.style.display = 'none'; progressDiv.style.maxWidth = '300px'; document.body.appendChild(progressDiv); button.addEventListener('click', function() { if (!isProcessing) { isProcessing = true; button.textContent = '处理中...'; button.disabled = true; allOrderData = []; // 清空之前的数据 currentPage = 0; clickTransactions(); } }); } function updateProgress(message) { const progressDiv = document.getElementById('epic-progress'); if (progressDiv) { progressDiv.style.display = 'block'; progressDiv.innerHTML = message; } } function clickTransactions() { const transactionsButton = document.querySelector('#nav-link-transactions'); if (transactionsButton) { transactionsButton.click(); console.log('点击了交易按钮'); updateProgress('正在加载交易页面...'); // 等待页面加载后开始提取数据 setTimeout(extractCurrentPageData, 2000); } else { console.log("找不到交易按钮。"); updateProgress('找不到交易按钮,请确保在正确的页面上。'); resetButton(); } } function extractCurrentPageData() { currentPage++; updateProgress(`正在处理第 ${currentPage} 页...`); // 查找所有订单行 - 使用更精确的选择器 const orderRows = document.querySelectorAll('tr[data-orderid]'); console.log(`第 ${currentPage} 页找到 ${orderRows.length} 个订单`); orderRows.forEach((row, index) => { try { const orderData = extractOrderDataFromRow(row); if (orderData) { allOrderData.push(orderData); console.log(`提取订单: ${orderData['游戏名称']} - ${orderData['付款金额']}`); } } catch (error) { console.error(`提取第 ${index + 1} 个订单数据时出错:`, error); } }); console.log(`第 ${currentPage} 页提取了 ${orderRows.length} 个订单,总计 ${allOrderData.length} 个订单`); // 检查是否有下一页 setTimeout(checkNextPage, 1000); } function extractOrderDataFromRow(row) { try { // 获取订单ID const orderId = row.getAttribute('data-orderid') || ''; // 获取订单信息单元格 (第二个td) const infoCell = row.querySelector('td:nth-child(2)'); if (!infoCell) { console.warn('找不到订单信息单元格'); return null; } // 提取日期 - 第一个div元素 const dateElement = infoCell.querySelector('div:first-child'); const orderDate = dateElement ? dateElement.textContent.trim() : ''; // 提取游戏名称 - 查找包含游戏名称的span元素 let gameName = ''; const gameNameElements = infoCell.querySelectorAll('.am-hoct6b'); if (gameNameElements.length > 0) { gameName = gameNameElements[0].textContent.trim(); } // 提取价格信息 - 查找包含"价格"文本的元素 let price = '0.00'; const priceElements = infoCell.querySelectorAll('.am-brjg0'); for (let element of priceElements) { if (element.textContent.includes('价格')) { const priceContainer = element.nextElementSibling; if (priceContainer && priceContainer.classList.contains('am-1v0j95h')) { const priceText = priceContainer.textContent.trim(); // 提取价格数字,处理 "¥0.00" 或 "- ¥0.00" 格式 const priceMatch = priceText.match(/[¥$]?([\d.,]+)/); if (priceMatch) { price = priceMatch[1]; } break; } } } // 提取商城信息 let marketplace = ''; for (let element of priceElements) { if (element.textContent.includes('商城')) { const marketplaceContainer = element.nextElementSibling; if (marketplaceContainer && marketplaceContainer.classList.contains('am-1v0j95h')) { marketplace = marketplaceContainer.textContent.trim(); break; } } } // 提取说明信息 let description = ''; for (let element of priceElements) { if (element.textContent.includes('说明')) { const descContainer = element.nextElementSibling; if (descContainer && descContainer.classList.contains('am-1v0j95h')) { const descElement = descContainer.querySelector('.am-1rqw9bo'); if (descElement) { description = descElement.textContent.trim(); } break; } } } return { '订单ID': orderId, '订单日期': orderDate, '游戏名称': gameName, '说明': description, '付款金额': price, '商城': marketplace, '页面': currentPage }; } catch (error) { console.error('提取订单数据时出错:', error); return null; } } function checkNextPage() { const nextButton = document.querySelector('#next-btn'); if (nextButton && !nextButton.disabled) { nextButton.click(); console.log('点击了下一页按钮'); updateProgress(`正在加载第 ${currentPage + 1} 页...`); // 等待页面加载后继续提取 setTimeout(extractCurrentPageData, 2000); } else { console.log("没有更多页面可以加载。"); updateProgress(`处理完成!共提取 ${allOrderData.length} 个订单。正在生成Excel文件...`); // 等待最后一页数据完全加载 setTimeout(exportData, 2000); } } function exportData() { if (allOrderData.length === 0) { alert('没有提取到任何订单数据,请检查页面是否正确加载。'); resetButton(); return; } console.log(`准备导出 ${allOrderData.length} 条订单数据`); const workbook = XLSX.utils.book_new(); const worksheet = XLSX.utils.json_to_sheet(allOrderData); XLSX.utils.book_append_sheet(workbook, worksheet, '订单历史'); XLSX.writeFile(workbook, `EPIC游戏订单历史_${new Date().toISOString().slice(0, 10)}.xlsx`); alert(`导出完成!共导出 ${allOrderData.length} 条订单数据。`); resetButton(); } function resetButton() { const button = document.getElementById('epic-export-btn'); const progressDiv = document.getElementById('epic-progress'); if (button) { button.textContent = '开始导出'; button.disabled = false; } if (progressDiv) { progressDiv.style.display = 'none'; } isProcessing = false; } createExportButton(); })();