您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Based on 淘宝买家订单导出 by CMA, added tracking number on top of it to the export data. Instructions are listed on GitHub
// ==UserScript== // @name Taobao orders export 淘宝订单快递导出 // @namespace http://tampermonkey.net/ // @version 0.1.0 // @description Based on 淘宝买家订单导出 by CMA, added tracking number on top of it to the export data. Instructions are listed on GitHub // @author Trizzy33 // @include https://buyertrade.taobao* // @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== //github https://github.com/Trizzy33/taobaoTrackingNumberExport/blob/main/script let orderList = []; let state = { orderList: [], isProcessing: false, shouldStop: false, currentWindow: null }; function addButton(parent, onClick, text) { const btn = document.createElement("input"); btn.type = "button"; btn.value = text; Object.assign(btn.style, { padding: "10px 20px", margin: "10px", backgroundColor: "#409EFF", border: "none", borderRadius: "8px", boxShadow: "0 2px 6px rgba(0,0,0,0.2)", color: "#fff", fontWeight: "bold", cursor: "pointer", transition: "all 0.2s ease" }); btn.onmouseenter = () => { btn.style.backgroundColor = "#66b1ff"; }; btn.onmouseleave = () => { btn.style.backgroundColor = "#409EFF"; }; btn.onclick = onClick; parent.insertBefore(btn, parent.firstChild); } if (/buyertrade\.taobao/.test(window.location.href)) { const main = document.getElementById("J_bought_main"); addButton(main, addCurrentPageOrdersToList, "添加本页订单"); addButton(main, exportOrders, "导出订单"); addButton(main, stopScript, "停止脚本"); } function toCsv(header, data, filename) { let rows = '\uFEFF' + header.join(',') + '\n'; for (let order of data) { // 防止 Excel 科学计数:加 \t order[0] = '\t' + order[0]; // 订单号 order[7] = order[7] ? '\t' + order[7] : ''; // 运单号 rows += order.join(',') + '\n'; } const blob = new Blob([rows], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = filename + ".csv"; document.body.appendChild(link); link.click(); document.body.removeChild(link); } function addCurrentPageOrdersToList() { if (state.isProcessing) return; state.isProcessing = true; state.shouldStop = false; const orders = document.querySelectorAll(".js-order-container"); processOrders(orders); } function exportOrders() { const header = ["订单号", "商品名称", "商品链接", "单价", "数量", "实付款", "状态", "快递单号"]; toCsv(header, orderList, "淘宝订单导出"); } function stopScript() { state.shouldStop = true; state.isProcessing = false; if (state.currentWindow && !state.currentWindow.closed) { state.currentWindow.close(); } if (state.orderList.length > 0) exportOrders(); } function processOrders(orders, current = 0, results = []) { if (current >= orders.length || state.shouldStop) { console.table(results); return results; } const order = orders[current]; const id = order.getAttribute('data-reactid')?.match(/order-(\d+)/)?.[1]; const statusText = order.querySelector("span[data-reactid*='.$5.0.0.0']")?.textContent || ''; if (statusText.includes("交易成功")) { return processOrders(orders, current + 1, results); // skip finished orders } processOrderItems(order, id, 0, [], (orderResults) => { orderList.push(orderResults); setTimeout(() => processOrders(orders, current + 1, results), 500); }); } function processOrderItems(order, id, index = 0, productNames = [], callback) { try { let productQuery = order.querySelector("span[data-reactid='.0.7:$order-" + id + ".$" + id + ".0.1:1:0.$" + index + ".$0.0.1.0.0.1']"); if (productQuery == null) { // 没有更多商品,结束处理,返回合并名称 const joinedNames = productNames.join('||') || ''; const queries = { itemUrl: order.querySelector("a[href]"), price: order.querySelector("span[data-reactid='.0.7:$order-" + id + ".$" + id + ".0.1:1:0.$0.$1.0.1.1']"), count: order.querySelector("p[data-reactid='.0.7:$order-" + id + ".$" + id + ".0.1:1:0.$0.$2.0.0']"), actualPay: order.querySelector("span[data-reactid='.0.7:$order-" + id + ".$" + id + ".0.1:1:0.$0.$4.0.0.2.0.1']"), status: order.querySelector("span[data-reactid='.0.7:$order-" + id + ".$" + id + ".0.1:1:0.$0.$5.0.0.0']"), tracking: order.querySelector("#viewLogistic") }; if (queries.status?.textContent === '交易成功') { callback(); // 跳过 return; } const orderItem = [ id, joinedNames, queries.itemUrl?.href || '', parseFloat(queries.price?.textContent || 0), queries.count?.textContent || '', queries.actualPay?.textContent || '', queries.status?.textContent || '' ]; if (queries.tracking) { getTrackingNumberViaHover(queries.tracking).then(trackingNumber => { orderItem.push(trackingNumber); callback(orderItem); }); } else { orderItem.push('0'); callback(orderItem); } return; } // 有商品,记录商品名后递归 productNames.push(productQuery.textContent.replace(/,/g, ",")); processOrderItems(order, id, index + 1, productNames, callback); } catch (e) { console.error(`处理订单 ${id} 时出错`, e); callback([]); } } async function getTrackingNumberViaHover(el) { return new Promise((resolve) => { if (state.shouldStop) return resolve('0'); ['mouseenter', 'mouseover'].forEach(e => el.dispatchEvent(new MouseEvent(e, { bubbles: true }))); const observer = new MutationObserver((mutations, obs) => { for (const m of mutations) { for (const node of m.addedNodes) { const tooltip = node.querySelector?.('.logistics-info-mod__header___gNRGw'); if (tooltip) { const match = tooltip.textContent.match(/\d{13,}/); if (match) { obs.disconnect(); return resolve(match[0]); } } } } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(() => { observer.disconnect(); resolve('0'); }, 4000); }); }