您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
采集分配记录并导出为Excel(支持iframe自动采集)
// ==UserScript== // @name 阿里国际站咨询分配记录采集导出 // @namespace http://tampermonkey.net/ // @version 1.5 // @description 采集分配记录并导出为Excel(支持iframe自动采集) // @author 树洞先生 // @license MIT // @match https://message.alibaba.com/message/default.htm* // @match https://message.alibaba.com/* // @run-at document-end // @grant none // ==/UserScript== (function() { 'use strict'; // 自动注入XLSX库到主页面(如果未定义) if (!window.XLSX) { const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/xlsx.full.min.js'; document.head.appendChild(script); } // 采集当前页数据(只采集指定字段) function parsePage() { const results = []; document.querySelectorAll('.assign-list-item').forEach(item => { const subject = item.querySelector('.inquiry-subject')?.innerText.trim() || ''; const contact_name = item.querySelector('.contact-name')?.innerText.trim() || ''; // 新增:采集买家邮箱,修正为通过.contact-email类获取 const contact_email = item.querySelector('.contact-email')?.innerText.trim() || ''; const assign_date = item.querySelector('.assign-date')?.innerText.trim() || ''; const assign_time = item.querySelector('.assign-time')?.innerText.trim() || ''; const assign_content = item.querySelector('.assign-content')?.innerText.trim() || ''; const assign_reason = item.querySelector('.assign-reason')?.innerText.trim() || ''; results.push({ '主题': subject, '买家': contact_name, '买家邮箱': contact_email, '分配日期': assign_date, '分配时间': assign_time, '分配人&被分配人': assign_content, '原因': assign_reason }); }); return results; } // 等待页面加载 function waitForSelector(selector, timeout = 30000) { return new Promise((resolve, reject) => { const interval = 200; let elapsed = 0; const timer = setInterval(() => { const el = document.querySelector(selector); if (el) { clearInterval(timer); resolve(el); } else if ((elapsed += interval) >= timeout) { clearInterval(timer); reject('Timeout'); } }, interval); }); } // 导出为Excel,列宽自适应,首列为序号 function exportToExcel(data) { // 增加序号列 const dataWithIndex = data.map((row, idx) => ({ '序号': idx + 1, ...row })); const ws = XLSX.utils.json_to_sheet(dataWithIndex); // 自动列宽 const cols = Object.keys(dataWithIndex[0] || {}).map(key => { const maxLen = Math.max( key.length, ...dataWithIndex.map(row => (row[key] ? String(row[key]).length : 0)) ); return { wch: maxLen + 2 }; }); ws['!cols'] = cols; const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "分配记录"); XLSX.writeFile(wb, "咨询分配明细.xlsx"); } // 翻页并采集所有数据,每采集一页就导出一次Excel async function collectAllPagesWithStepExport(btn) { let allResults = []; let page = 1; let lastFirstId = null; let failCount = 0; const maxFail = 3; // 连续3次超时则停止 while (true) { btn.innerText = `采集中...第${page}页`; try { await waitForSelector('.assign-list-item', 60000); // 超时60秒 } catch (e) { console.warn(`第${page}页超时,跳过!`); failCount++; if (failCount >= maxFail) { console.error('连续多页超时,采集终止。'); break; } // 尝试点击下一页 const nextBtn = document.querySelector('.next-pagination-item.next-next:not([disabled])'); if (nextBtn && !nextBtn.classList.contains('next-btn-disabled')) { nextBtn.click(); page++; await new Promise(r => setTimeout(r, 1000)); continue; } else { break; } } failCount = 0; // 成功采集后重置失败计数 let firstItem = document.querySelector('.assign-list-item'); let firstId = firstItem ? firstItem.innerText : ''; if (lastFirstId && firstId === lastFirstId) { await new Promise(r => setTimeout(r, 500)); continue; } lastFirstId = firstId; const pageData = parsePage(); allResults = allResults.concat(pageData); console.log(`已采集第${page}页,本页${pageData.length}条,总计${allResults.length}条`); // 不再每页导出 // exportToExcel(allResults); const nextBtn = document.querySelector('.next-pagination-item.next-next:not([disabled])'); if (nextBtn && !nextBtn.classList.contains('next-btn-disabled')) { nextBtn.click(); page++; await new Promise(r => setTimeout(r, 1000)); } else { break; } } // 只在全部采集完成后导出一次 exportToExcel(allResults); return allResults; } // 添加按钮到页面 function addExportButton() { if (document.getElementById('export-assign-btn')) return; const btn = document.createElement('button'); btn.id = 'export-assign-btn'; btn.innerText = '导出分配记录Excel'; btn.style.background = '#ff9900'; btn.style.color = '#fff'; btn.style.border = 'none'; btn.style.padding = '8px 15px'; btn.style.fontSize = '14px'; btn.style.borderRadius = '6px'; btn.style.cursor = 'pointer'; btn.style.marginLeft = '24px'; btn.onclick = async function() { btn.innerText = '检测数据加载中...'; btn.disabled = true; let tryCount = 0; while (document.querySelectorAll('.assign-list-item').length === 0 && tryCount < 120) { await new Promise(r => setTimeout(r, 500)); tryCount++; } if (document.querySelectorAll('.assign-list-item').length === 0) { alert('页面数据长时间未加载,请确认已登录且无验证码/滑块,再重试!'); btn.innerText = '导出分配记录Excel'; btn.disabled = false; return; } btn.innerText = '采集中...'; try { await collectAllPagesWithStepExport(btn); alert('采集完成,已保存为 咨询分配明细.xlsx'); } catch (e) { alert('采集失败: ' + e + '\n已采集数据已保存到 咨询分配明细.xlsx'); } btn.innerText = '导出分配记录Excel'; btn.disabled = false; }; // 插入到 h1.assign-log-title 右侧,使用 flex 容器 const h1 = document.querySelector('h1.assign-log-title'); if (h1 && h1.parentNode) { // 检查是否已包裹在 flex 容器 let flexDiv = h1.parentNode; if (!flexDiv.classList.contains('ai-flex-row')) { // 创建 flex 容器 flexDiv = document.createElement('div'); flexDiv.style.display = 'flex'; flexDiv.style.alignItems = 'center'; flexDiv.className = 'ai-flex-row'; h1.parentNode.insertBefore(flexDiv, h1); flexDiv.appendChild(h1); } flexDiv.appendChild(btn); } else { document.body.appendChild(btn); } } // 自动检测当前页面或iframe,插入按钮 function tryInject() { // 如果当前页面有数据,直接插入按钮 if (document.querySelectorAll('.assign-list-item').length > 0) { addExportButton(); return; } // 否则查找inquiry-assign-log-iframe const iframe = document.getElementById('inquiry-assign-log-iframe'); if (iframe && iframe.contentWindow) { // 注入XLSX库并等待其可用 function injectXLSXandButton() { function waitForXLSXAndInject() { if (iframe.contentWindow.XLSX) { iframe.contentWindow.eval('(' + addExportButton.toString() + ')();'); } else { setTimeout(waitForXLSXAndInject, 100); } } if (!iframe.contentWindow.XLSX) { const script = iframe.contentDocument.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/xlsx.full.min.js'; script.onload = waitForXLSXAndInject; iframe.contentDocument.head.appendChild(script); } else { waitForXLSXAndInject(); } } iframe.addEventListener('load', injectXLSXandButton); // 如果iframe已加载,立即注入 if (iframe.contentDocument && iframe.contentDocument.readyState === 'complete') { injectXLSXandButton(); } } } // 页面加载后自动检测并注入 window.addEventListener('load', tryInject); })();