Greasy Fork is available in English.
精确提取EPIC游戏订单信息,基于HTML表格结构,包括付款金额、游戏名称、订单日期等。
当前为
// ==UserScript==
// @name EPIC游戏库存导出
// @namespace http://tampermonkey.net/
// @version 1.3
// @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
// ==/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();
})();