// ==UserScript== // @name 网页表格导出 // @namespace http://tampermonkey.net/ // @version 1.1 // @description 在网页表格右上角添加导出按钮,支持导出为XLSX文件,处理长数字精度问题,监测网页实时变化 // @author hanj-cn@qq.com // @match *://*/* // @grant none // @require https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js // @license MIT // ==/UserScript== (function () { 'use strict'; // 等待XLSX库加载完成 function waitForXLSX() { if (typeof XLSX !== 'undefined') { // XLSX库已加载,初始化脚本 initScript(); } else { // 等待100毫秒后重试 setTimeout(waitForXLSX, 100); } } // 初始化脚本 function initScript() { // 等待页面加载完成 window.addEventListener('load', function () { // 查找所有表格 const tables = document.querySelectorAll('table'); tables.forEach(table => { // 为每个表格添加导出按钮 addExportButton(table); }); // 设置MutationObserver监测网页变化 setupMutationObserver(); }); } // 设置MutationObserver监测网页变化 function setupMutationObserver() { const observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { // 检查是否有新的表格添加 if (mutation.type === 'childList') { // 查找新添加的表格 const newTables = mutation.addedNodes; newTables.forEach(function (node) { if (node.nodeType === Node.ELEMENT_NODE) { // 检查节点本身是否是表格 if (node.tagName === 'TABLE') { addExportButton(node); } // 检查节点的子元素中是否有表格 const tablesInNode = node.querySelectorAll('table'); tablesInNode.forEach(function (table) { addExportButton(table); }); } }); } }); }); // 配置观察选项 const config = { childList: true, subtree: true }; // 开始观察文档根节点 observer.observe(document.body, config); } // 添加导出按钮 function addExportButton(table) { // 创建按钮 const button = document.createElement('button'); button.textContent = '导表'; // 设置按钮样式 button.style.position = 'absolute'; button.style.top = '5px'; button.style.right = '5px'; button.style.zIndex = '1000'; button.style.padding = '3px 6px'; button.style.backgroundColor = 'rgba(34, 116, 71, 0.4)'; // xlsx绿色,更透明 button.style.color = 'white'; button.style.border = '1px solid rgba(34, 116, 71, 0.5)'; button.style.borderRadius = '3px'; button.style.cursor = 'pointer'; button.style.fontSize = '10px'; button.style.transition = 'all 0.3s'; button.style.minWidth = '40px'; button.style.textAlign = 'center'; // 鼠标悬停时增加不透明度 button.addEventListener('mouseover', function () { button.style.backgroundColor = 'rgba(34, 116, 71, 0.7)'; // 悬停时增加透明度 }); button.addEventListener('mouseout', function () { button.style.backgroundColor = 'rgba(34, 116, 71, 0.4)'; }); // 为表格的父元素设置相对定位 const parent = table.parentElement; if (parent.style.position === '' || parent.style.position === 'static') { parent.style.position = 'relative'; } // 将按钮添加到表格的父元素中 parent.appendChild(button); // 点击按钮导出表格 button.addEventListener('click', function () { exportTableToXLSX(table); }); } /* 安全文件名:保留中文、字母、数字、部分符号,其余变 _,合并连续 _,去头尾,长度 30 */ function safeFileName(rawTitle) { const txt = (rawTitle || 'table').replace(/&[a-zA-Z0-9#]+;/g, ' ').trim(); let s = txt.replace(/[^\u4e00-\u9fa5\u3040-\u309f\u30a0-\u30ff\uac00-\ud7afa-zA-Z0-9\-_. ]/g, '_'); s = s.replace(/_+/g, '_').replace(/^_|_$/g, ''); if (!s) s = 'table'; return s.substring(0, 30); } // 导出表格为XLSX function exportTableToXLSX(table) { // 检查XLSX库是否可用 if (typeof XLSX === 'undefined') { alert('XLSX库未加载,请刷新页面重试'); return; } try { // 预处理表格中的超长数字,将其转换为文本 table.querySelectorAll('td, th').forEach(cell => { const text = cell.textContent.trim(); if (/^\d+(\.\d+)?$/.test(text) && text.replace(/\./, '').length > 11) { // 创建一个新的文本节点,替换原内容 const textNode = document.createTextNode(text); cell.innerHTML = "'"; cell.appendChild(textNode); // 添加数据属性标记为已处理 cell.dataset.processed = 'true'; } }); // 创建工作簿 const wb = XLSX.utils.book_new(); // 使用table_to_sheet方法创建工作表(自动处理合并单元格) const ws = XLSX.utils.table_to_sheet(table); // 将工作表添加到工作簿 XLSX.utils.book_append_sheet(wb, ws, '数据'); // 生成文件名 const now = new Date(); const date = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}`; // 获取网页标题 let siteName = document.title.trim(); // 尝试获取表格标题 let tableTitle = ''; // 查找表格附近的标题元素 const possibleTitles = table.parentNode.querySelectorAll('h1, h2, h3, h4, h5, h6'); if (possibleTitles.length > 0) { tableTitle = possibleTitles[0].textContent.trim(); } // 如果没有找到标题,尝试查找表格的caption if (!tableTitle) { const caption = table.querySelector('caption'); if (caption) { tableTitle = caption.textContent.trim(); } } const safeSiteName = safeFileName(siteName); const safeTableTitle = safeFileName(tableTitle); // 组合文件名 let fileNameParts = [date, safeSiteName]; if (safeTableTitle) { fileNameParts.push(safeTableTitle); } fileNameParts.push(now.getTime()); const fileName = `${fileNameParts.join('_')}.xlsx`; // 导出文件 XLSX.writeFile(wb, fileName); } catch (error) { console.error('导出失败:', error); alert('导出失败,请检查控制台错误信息'); } } // 开始等待XLSX库加载 waitForXLSX(); })();