// ==UserScript== // @name TEMU商品卡定位 // @namespace http://tampermonkey.net/ // @version 5.1 // @description tfind + 商品图片一键下载 // @author binning // @match https://www.temu.com/* // @grant none // ==/UserScript== (function () { 'use strict'; const style = document.createElement('style'); style.textContent = ` * { margin: 0; padding: 0; box-sizing: border-box; } /* 悬浮触发小圆点 */ .tool-float-btn { position: fixed; left: 15px; top: 15px; width: 44px; height: 44px; border-radius: 50%; background: #409eff; color: #fff; font-size: 18px; font-weight: bold; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 100000; box-shadow: 0 4px 15px rgba(64,158,255,0.35); user-select: none; transition: all 0.25s ease; } .tool-float-btn:hover { transform: scale(1.08); background: #66b1ff; } /* 主工具面板 */ .goods-tool-panel { position: fixed; left: 15px; top: 15px; z-index: 99999; background: #ffffff; width:600px; border-radius: 12px; box-shadow: 0 8px 30px rgba(0,0,0,0.12); overflow: hidden; border: 1px solid #ebeef5; font-family: "Microsoft Yahei", sans-serif; display: none; } .tool-header { padding: 14px 18px; background: #f7f8fa; border-bottom: 1px solid #ebeef5; display: flex; align-items: center; gap: 12px; } .tool-header .refresh-btn, .tool-header .export-btn, .tool-header .downloadAll-btn { padding: 7px 16px; border: none; border-radius: 8px; cursor: pointer; font-size: 13px; transition: all 0.2s ease; } .refresh-btn { background: #409eff; color: #fff; } .refresh-btn:hover { background: #66b1ff; } .export-btn { background: #67c23a; color: #fff; } .export-btn:hover { background: #85ce61; } .downloadAll-btn { background: #e6a23c; color: #fff; } .downloadAll-btn:hover { background: #ebb563; } .tool-header label { font-size: 13px; color: #606266; user-select: none; display: flex; align-items: center; gap: 6px; cursor: pointer; } .tool-header input[type="checkbox"] { width: 15px; height: 15px; cursor: pointer; } table td:nth(2)-child{ width:100px } table td:last-child{ width:190px } .table-body { max-height: 550px; overflow-y: auto; } .table-body::-webkit-scrollbar { width: 6px; } .table-body::-webkit-scrollbar-thumb { background: #dcdfe6; border-radius: 3px; } .table-body::-webkit-scrollbar-track { background: #f5f7fa; } #goodsTable { width: 100%; border-collapse: collapse; font-size: 12.5px; color: #303133; } #goodsTable th { position: sticky; top: 0; background: #f5f7fa; z-index: 10; font-weight: 500; color: #606266; } #goodsTable th, #goodsTable td { border: 1px solid #ebeef5; padding: 9px 6px; text-align: center; } #goodsTable th { cursor: pointer; user-select: none; transition: background 0.2s; } #goodsTable th:hover { background: #ecf5ff; } #goodsTable tbody tr:hover { background: #fafafa; } #goodsTable .title { cursor: pointer; max-width: 150px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: #303133; } #goodsTable .title:hover { color: #409eff; } #goodsTable .preview-img { width: 52px; height: 52px; object-fit: cover; cursor: pointer; border-radius: 6px; transition: transform 0.2s; } #goodsTable .preview-img:hover { transform: scale(1.08); } .pos-btn { background: #409eff; color: #fff; border: none; padding: 5px 10px; border-radius: 6px; cursor: pointer; font-size: 12px; transition: all 0.2s; } .pos-btn:hover { background: #66b1ff; } .download-btn { background: #67c23a; color: #fff; border: none; padding: 5px 10px; border-radius: 6px; cursor: pointer; font-size: 12px; margin-left: 5px; transition: all 0.2s; } .download-btn:hover { background: #85ce61; } .del-btn { background: #f56c6c; color: #fff; border: none; padding: 5px 10px; border-radius: 6px; cursor: pointer; font-size: 12px; margin-left: 5px; transition: all 0.2s; } .del-btn:hover { background: #f78989; } .img-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); display: none; justify-content: center; align-items: center; z-index: 100000; cursor: zoom-out; } .img-modal img { max-width: 90%; max-height: 90%; border-radius: 10px; box-shadow: 0 10px 40px rgba(0,0,0,0.3); } .highlight-goods { animation: highlight 1.4s ease; border: 3px solid #409eff !important; border-radius: 8px; box-sizing: border-box; } @keyframes highlight { 0% { background: rgba(64,158,255,0.1); } 50% { background: rgba64,158,255,0.2); } 100% { background: transparent; } } `; document.head.appendChild(style); // 悬浮圆点 const floatBtn = document.createElement('div'); floatBtn.className = 'tool-float-btn'; floatBtn.innerText = 'T'; document.body.appendChild(floatBtn); // 主面板 const panel = document.createElement('div'); panel.className = 'goods-tool-panel'; panel.innerHTML = `
`; document.body.appendChild(panel); // 展开/收缩切换 let panelShow = false; floatBtn.onclick = () => { panelShow = !panelShow; panel.style.display = panelShow ? 'block' : 'none'; }; // 图片放大弹窗 const imgModal = document.createElement('div'); imgModal.className = 'img-modal'; const modalImg = document.createElement('img'); imgModal.appendChild(modalImg); document.body.appendChild(imgModal); imgModal.onclick = () => imgModal.style.display = 'none'; let currentData = []; let sortField = 'index'; let sortOrder = 'asc'; let onlyHasSales = false; // 清理文件名非法字符 function safeFileName(name) { return name.replace(/[\\/:*?"<>|]/g, '_').trim(); } function cleanImgSrc(src) { if (!src) return ''; return src.split('?')[0]; } function parseSales(text) { if (!text) return 0; let lower = text.toLowerCase().trim(); if (lower.includes('万')) { let num = lower.replace(/[^\d.]/g, ''); return parseFloat(num) * 10000 || 0; } let numStr = lower.replace(/[^\d]/g, ''); return parseInt(numStr) || 0; } function getSalesNumber(text) { return parseSales(text); } function escapeHtml(str) { return str?.replace(/"/g, '"').replace(//g, '>') || ''; } // 下载图片:文件名 = 销量 标题 async function downloadImage(url, salesText, title) { if (!url) return; // 拼接:销量 标题 let fileName = `${salesText} ${title}`; fileName = safeFileName(fileName); try { const response = await fetch(url, { mode: 'cors' }); const blob = await response.blob(); const blobUrl = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = blobUrl; a.download = fileName + '.jpg'; document.body.appendChild(a); a.click(); setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(blobUrl); }, 100); } catch (err) { const a = document.createElement('a'); a.href = url; a.download = fileName + '.jpg'; document.body.appendChild(a); a.click(); document.body.removeChild(a); } } // 下载全部图片 async function downloadAllImages() { const rows = document.querySelectorAll('#goodsTable tr:not(:first-child)'); if (!rows.length) { alert('暂无图片可下载'); return; } let count = 0; for (const tr of rows) { const img = tr.cells[3].querySelector('img'); const src = img?.dataset?.fullsrc; const salesText = tr.cells[2].textContent.trim(); const title = tr.cells[1].dataset.full || '无标题'; if (src) { await downloadImage(src, salesText, title); count++; await new Promise(r => setTimeout(r, 300)); } } alert(`批量下载完成!\n成功下载 ${count} 张图片`); } function fetchData() { const goodsList = [...document.querySelectorAll('.EKDT7a3v'), ...document.querySelectorAll('._2gR7cTnt')]; const data = []; goodsList.forEach((item, idx) => { const titleEl = item.querySelector('._2D9RBAXL'); let salesText = '暂无销量'; const wrapNd = item.querySelector('._7LLqXcNd'); if (wrapNd) { const saleItems = wrapNd.querySelectorAll('._2XgTiMJi'); if (saleItems.length) { const lastSale = saleItems[saleItems.length - 1]; salesText = lastSale.textContent.trim(); } } const imgEl = item.querySelector('.goods-img-external'); const rawSrc = imgEl?.src || ''; const cleanSrc = cleanImgSrc(rawSrc); data.push({ index: idx, title: titleEl ? titleEl.textContent.trim() : '无标题', salesText: salesText, sales: parseSales(salesText), rawSrc: rawSrc, cleanSrc: cleanSrc, element: item }); }); currentData = data; } function sortData() { currentData.sort((a, b) => { if (sortField === 'index') return a.index - b.index; if (sortField === 'sales') return sortOrder === 'asc' ? a.sales - b.sales : b.sales - a.sales; if (sortField === 'title') return sortOrder === 'asc' ? a.title.localeCompare(b.title) : b.title.localeCompare(a.title); return 0; }); } function renderTable() { fetchData(); sortData(); const showData = onlyHasSales ? currentData.filter(i => i.sales > 0) : currentData; let html = ` `; showData.forEach((item, i) => { html += ` `; }); html += '
序号 标题 销量 预览图 操作
${i + 1} ${item.title} ${item.salesText}
'; document.querySelector('.table-body').innerHTML = html; const rows = document.querySelectorAll('#goodsTable tbody tr'); showData.forEach((item, i) => { rows[i].dataItem = item; }); bindEvents(); } function bindEvents() { document.querySelectorAll('#goodsTable .title').forEach(el => { el.onclick = () => navigator.clipboard.writeText(el.dataset.full) .then(() => alert('已复制标题')) .catch(() => alert('复制失败')); }); document.querySelectorAll('.preview-img').forEach(el => { el.onclick = () => { modalImg.src = el.dataset.fullsrc; imgModal.style.display = 'flex'; }; }); document.querySelectorAll('.pos-btn').forEach(btn => { btn.onclick = () => { const row = btn.closest('tr'); const item = row.dataItem; if (!item || !item.element) return; item.element.scrollIntoView({ behavior: 'smooth', block: 'center' }); item.element.classList.add('highlight-goods'); setTimeout(() => item.element.classList.remove('highlight-goods'), 1400); }; }); // 单个下载:传销量+标题 document.querySelectorAll('.download-btn').forEach(btn => { btn.onclick = () => { const row = btn.closest('tr'); const item = row.dataItem; const salesText = row.cells[2].textContent.trim(); if (!item || !item.cleanSrc) { alert('暂无图片可下载'); return; } downloadImage(item.cleanSrc, salesText, item.title); }; }); document.querySelectorAll('.del-btn').forEach(btn => { btn.onclick = () => btn.closest('tr').remove(); }); document.querySelectorAll('#goodsTable th[data-sort]').forEach(th => { th.onclick = () => { if (sortField === th.dataset.sort) { sortOrder = sortOrder === 'asc' ? 'desc' : 'asc'; } else { sortField = th.dataset.sort; sortOrder = 'asc'; } renderTable(); }; }); } function exportCSV() { const rows = document.querySelectorAll('#goodsTable tr:not(:first-child)'); if (!rows.length) { alert('暂无数据可导出'); return; } let csv = '\ufeff序号,商品标题,销量,图片地址\r\n'; rows.forEach(tr => { const seq = tr.cells[0].textContent.trim(); const title = `"${tr.cells[1].dataset.full.replace(/"/g, '""')}"`; const salesText = tr.cells[2].textContent.trim(); const salesNum = getSalesNumber(salesText); const img = tr.cells[3].querySelector('img').dataset.fullsrc; csv += `${seq},${title},${salesNum},${img}\r\n`; }); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = '商品数据.csv'; a.click(); URL.revokeObjectURL(a.href); } // 绑定按钮事件 document.querySelector('.refresh-btn').onclick = renderTable; document.querySelector('.export-btn').onclick = exportCSV; document.querySelector('.downloadAll-btn').onclick = downloadAllImages; document.getElementById('onlySalesCheck').addEventListener('change', e => { onlyHasSales = e.target.checked; renderTable(); }); // 初始渲染 window.addEventListener('load', () => { renderTable(); }); })();