您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
提取表格、flex容器、图片URL、名称、PDF下载链接及存放位置并上传
当前为
// ==UserScript== // @name 元器件信息提取 // @namespace http://tampermonkey.net/ // @version 1.7.5 // @description 提取表格、flex容器、图片URL、名称、PDF下载链接及存放位置并上传 // @author lzq-hopego // @match https://item.szlcsc.com/* // @exclude https://item.szlcsc.com/datasheet/* // @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net // @grant GM_xmlhttpRequest // @connect 127.0.0.1 // @license MIT // ==/UserScript== (function() { 'use strict'; // 创建悬浮框样式 const style = document.createElement('style'); style.textContent = ` .float-container { position: fixed; top: 20px; right: 20px; background: white; padding: 15px; border: 1px solid #ccc; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); z-index: 9999; width: 300px; user-select: none; } .float-container.collapsed { width: 120px; padding: 5px; transition: all 0.3s ease; } .float-container .title { margin: 0 0 10px 0; font-size: 16px; color: #333; } .float-container.collapsed .title { margin: 0; font-size: 14px; text-align: center; } .float-container .input-group { margin-bottom: 10px; } .float-container .drag-handle { cursor: move; text-align: center; padding: 5px; background: #f5f5f5; margin: -15px -15px 10px -15px; border-bottom: 1px solid #eee; border-radius: 8px 8px 0 0; user-select: none; } .float-container.collapsed .drag-handle { margin: -5px -5px 5px -5px; padding: 3px; } .float-container label { display: block; margin-bottom: 5px; font-size: 14px; color: #666; } .float-container input { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; } .float-container input.invalid { border-color: #ff4444; } .float-container .error-message { color: #ff4444; font-size: 12px; margin-top: 3px; display: none; } .float-container button { width: 100%; padding: 8px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; transition: background 0.3s; } .float-container button:hover { background: #0056b3; } .status-message { margin-top: 10px; padding: 8px; border-radius: 4px; font-size: 13px; display: none; } .status-success { background-color: #dff0d8; color: #3c763d; display: block; } .status-error { background-color: #f2dede; color: #a94442; display: block; } .debug-info { margin-top: 10px; font-size: 12px; color: #666; max-height: 100px; overflow-y: auto; display: none; } .show-debug { display: block; } .content-wrapper { transition: all 0.3s ease; } .float-container.collapsed .content-wrapper { display: none; } .float-container.dragging { transition: none !important; opacity: 0.9; } `; document.head.appendChild(style); // 创建悬浮框 const floatContainer = document.createElement('div'); floatContainer.className = 'float-container'; floatContainer.innerHTML = ` <div class="drag-handle">拖动/双击收起</div> <h3 class="title">数据上传配置</h3> <div class="content-wrapper"> <div class="input-group"> <label for="upload-domain">上传域名</label> <input type="text" id="upload-domain" placeholder="例如: http://127.0.0.1" value="http://127.0.0.1"> </div> <div class="input-group"> <label for="storage-location">存放位置</label> <input type="text" id="storage-location" placeholder="例如: A1-1-1" value="A1-1-1"> </div> <div class="input-group"> <label for="stock-quantity">库存数量</label> <input type="number" id="stock-quantity" placeholder="大于等于0的数字" min="0" value="0"> <div class="error-message" id="stock-error">请输入大于等于0的数字</div> </div> <button id="submit-btn">提取并上传数据</button> <div class="status-message" id="status"></div> <div class="debug-info" id="debug-info">调试信息将显示在这里</div> </div> `; document.body.appendChild(floatContainer); // 获取DOM元素 const dragHandle = floatContainer.querySelector('.drag-handle'); const domainInput = document.getElementById('upload-domain'); const locationInput = document.getElementById('storage-location'); const stockInput = document.getElementById('stock-quantity'); const stockError = document.getElementById('stock-error'); const submitBtn = document.getElementById('submit-btn'); const statusElement = document.getElementById('status'); const debugInfo = document.getElementById('debug-info'); // 双击和拖动事件处理 - 修复双击失灵问题 let isCollapsed = false; let clickCount = 0; let clickTimer = null; let isDragging = false; let lastClickTime = 0; const DOUBLE_CLICK_DELAY = 300; // 延长双击检测时间到300ms // 双击处理 dragHandle.addEventListener('click', function(e) { // 如果正在拖动,不处理点击事件 if (isDragging) return; const now = Date.now(); // 检查是否在双击时间窗口内 if (now - lastClickTime < DOUBLE_CLICK_DELAY) { // 双击操作 e.preventDefault(); isCollapsed = !isCollapsed; if (isCollapsed) { floatContainer.classList.add('collapsed'); } else { floatContainer.classList.remove('collapsed'); } // 重置点击跟踪 clickCount = 0; lastClickTime = 0; return; } // 第一次点击,记录时间 lastClickTime = now; clickCount = 1; }); // 初始化拖动功能 makeDraggable(floatContainer); // 库存输入验证 stockInput.addEventListener('input', function() { const value = parseFloat(this.value); if (isNaN(value) || value < 0) { this.classList.add('invalid'); stockError.style.display = 'block'; return false; } else { this.classList.remove('invalid'); stockError.style.display = 'none'; return true; } }); // 提交按钮点击事件 submitBtn.addEventListener('click', function() { // 显示调试信息 debugInfo.classList.add('show-debug'); debugInfo.innerHTML = '开始提取数据...<br>'; // 验证库存输入 const stockValue = parseFloat(stockInput.value); if (isNaN(stockValue) || stockValue < 0) { stockInput.classList.add('invalid'); stockError.style.display = 'block'; showDebug('库存数量输入无效'); return; } // 获取存放位置 const locationValue = locationInput.value.trim(); showDebug(`存放位置: ${locationValue}`); // 获取域名并构建URL let domain = domainInput.value.trim(); if (!domain) { showStatus('请输入上传域名', 'error'); showDebug('未输入上传域名'); return; } if (domain.endsWith('/')) { domain = domain.slice(0, -1); } const uploadUrl = `${domain}/api/post/components/`; showDebug(`上传URL: ${uploadUrl}`); // 提取各类数据 const tableData = extractTableData(); if (!tableData) { showStatus('未找到有效表格数据', 'error'); return; } const flexData = extractFlexData(); if (!flexData) { showDebug('未找到任何flex容器数据'); } const imageUrls = extractImageUrls(); if (imageUrls.length > 0) { showDebug(`成功提取 ${imageUrls.length} 个图片URL`); } else { showDebug('未找到任何图片URL'); } const nameValue = extractNameData(); if (nameValue) { showDebug(`提取到名称数据: ${nameValue}`); } else { showDebug('未找到名称数据'); } const manualUrl = extractDataManualUrl(); if (manualUrl) { showDebug(`提取到数据手册URL: ${manualUrl}`); } else { showDebug('未找到数据手册下载链接'); } // 合并所有数据 const allData = { ...tableData, ...flexData, stock: stockValue, img: imageUrls, name: nameValue, '数据手册': manualUrl, location: locationValue }; showDebug(`合并后的数据总数: ${Object.keys(allData).length}`); console.log('合并后的数据:', allData); // 上传数据 uploadData(uploadUrl, allData); }); // 提取表格数据 function extractTableData() { const targetTables = document.querySelectorAll('table.w-full.caption-bottom.text-sm'); if (!targetTables || targetTables.length < 2) { const message = `找到 ${targetTables ? targetTables.length : 0} 个目标表格,需要至少2个`; showDebug(message); return null; } showDebug(`找到 ${targetTables.length} 个目标表格,开始提取数据`); const allTableData = {}; targetTables.forEach((table, tableIndex) => { const tableBody = table.querySelector('tbody'); if (!tableBody) { showDebug(`表格 ${tableIndex + 1} 中未找到tbody元素`); return; } const rows = tableBody.querySelectorAll('tr'); if (rows.length === 0) { showDebug(`表格 ${tableIndex + 1} 的tbody中未找到任何行数据`); return; } showDebug(`表格 ${tableIndex + 1} 包含 ${rows.length} 行数据`); rows.forEach((row, rowIndex) => { const cells = row.querySelectorAll('td'); if (cells.length >= 3) { const key = cells[1].textContent.trim(); const value = cells[2].textContent.trim(); if (key && value) { allTableData[key] = value; showDebug(`表格 ${tableIndex + 1} 行 ${rowIndex + 1}: ${key} = ${value}`); } } else { showDebug(`表格 ${tableIndex + 1} 行 ${rowIndex + 1}: 单元格数量不足3个,跳过`); } }); }); return Object.keys(allTableData).length > 0 ? allTableData : null; } // 提取flex容器中的dt/dd数据 function extractFlexData() { const flexContainers = document.querySelectorAll('div.flex[class*="mt-\\[16px\\]"]'); if (!flexContainers || flexContainers.length === 0) { showDebug('未找到任何flex容器'); return null; } showDebug(`找到 ${flexContainers.length} 个flex容器,开始提取数据`); const flexData = {}; flexContainers.forEach((container, containerIndex) => { const dtElements = container.querySelectorAll('dt'); if (dtElements.length === 0) { showDebug(`flex容器 ${containerIndex + 1} 中未找到dt元素`); return; } dtElements.forEach((dt, dtIndex) => { const key = dt.textContent.trim(); if (!key) { showDebug(`flex容器 ${containerIndex + 1} 中dt ${dtIndex + 1} 为空`); return; } let ddElement = dt.nextElementSibling; if (ddElement && ddElement.tagName.toLowerCase() !== 'dd') { ddElement = dt.parentElement.querySelector('dd'); } if (ddElement && ddElement.tagName.toLowerCase() === 'dd') { const ddText = ddElement.textContent.trim(); let value = ddText; if (key.includes('参考')) { showDebug(`flex容器 ${containerIndex + 1} dt ${dtIndex + 1}: 发现包含"参考"的dt内容`); const aTag = ddElement.querySelector('a'); if (aTag && aTag.href) { value = aTag.href; showDebug(`flex容器 ${containerIndex + 1} dt ${dtIndex + 1}: 提取a标签href: ${value}`); } else { showDebug(`flex容器 ${containerIndex + 1} dt ${dtIndex + 1}: 未找到a标签,使用dd文本值`); } } flexData[key] = value; showDebug(`flex容器 ${containerIndex + 1} dt ${dtIndex + 1}: ${key} = ${value}`); } else { showDebug(`flex容器 ${containerIndex + 1} 中dt ${dtIndex + 1} (${key}) 未找到对应的dd元素`); } }); }); return Object.keys(flexData).length > 0 ? flexData : null; } // 提取图片URL function extractImageUrls() { const imageUrls = []; const targetUl = document.querySelector('ul.flex-1.flex.items-center.justify-center'); if (!targetUl) { showDebug('未找到class为"flex-1 flex items-center justify-center"的ul元素'); return imageUrls; } const listItems = targetUl.querySelectorAll('li'); if (!listItems || listItems.length === 0) { showDebug('找到目标ul,但未包含任何li元素'); return imageUrls; } showDebug(`找到目标ul,包含 ${listItems.length} 个li元素,开始提取图片URL`); listItems.forEach((li, index) => { const imgElement = li.querySelector('img'); if (imgElement && imgElement.src) { let imgUrl = imgElement.src.replace('breviary', 'source'); imageUrls.push(imgUrl); showDebug(`li元素 ${index + 1}: 提取并处理URL - ${imgUrl}`); } else { showDebug(`li元素 ${index + 1}: 未找到有效img元素或src属性`); } }); return imageUrls; } // 提取名称数据 function extractNameData() { const nameParagraph = document.querySelector('div.text-\\[14px\\].mb-\\[20px\\] p'); if (!nameParagraph) { showDebug('未找到class为"text-[14px] mb-[20px]"的div下的p标签,尝试通用选择器'); const generalParagraph = document.querySelector('.text-\\[14px\\].mb-\\[20px\\] p'); if (generalParagraph) { return generalParagraph.textContent.trim(); } return null; } return nameParagraph.textContent.trim(); } // 提取数据手册PDF下载链接 function extractDataManualUrl() { const pdfLink = document.querySelector('a#item-pdf-down'); if (!pdfLink) { showDebug('未找到id为"item-pdf-down"的a标签'); return null; } if (!pdfLink.href) { showDebug('找到id为"item-pdf-down"的a标签,但未包含href属性'); return null; } return pdfLink.href; } // 上传数据 function uploadData(url, data) { showDebug('开始上传数据...'); showStatus('正在上传数据...', 'success'); GM_xmlhttpRequest({ method: 'POST', url: url, headers: { 'Content-Type': 'application/json' }, data: JSON.stringify(data), onload: function(response) { console.log('数据上传成功,服务器响应:', response.responseText); showDebug(`上传成功,服务器响应状态: ${response.status}`); showStatus('数据上传成功!', 'success'); }, onerror: function(error) { console.error('数据上传失败:', error); showDebug(`上传失败: ${error.message}`); showStatus('数据上传失败', 'error'); }, onabort: function() { console.log('请求已中止'); showDebug('请求已中止'); showStatus('请求已中止', 'error'); }, ontimeout: function() { console.log('请求超时'); showDebug('请求超时'); showStatus('请求超时', 'error'); } }); } // 显示状态消息 function showStatus(message, type) { statusElement.textContent = message; statusElement.className = 'status-message'; statusElement.classList.add(`status-${type}`); if (type === 'success') { setTimeout(() => { statusElement.className = 'status-message'; }, 3000); } } // 显示调试信息 function showDebug(message) { const timestamp = new Date().toLocaleTimeString(); debugInfo.innerHTML += `[${timestamp}] ${message}<br>`; debugInfo.scrollTop = debugInfo.scrollHeight; } // 拖动功能实现 - 兼顾双击识别 function makeDraggable(element) { let offsetX, offsetY; const handle = element.querySelector('.drag-handle'); let dragStartX, dragStartY; const DRAG_THRESHOLD = 5; // 拖动阈值,像素 function startDrag(e) { // 记录初始拖动位置 dragStartX = e.clientX; dragStartY = e.clientY; const rect = element.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; // 使用捕获阶段监听 document.addEventListener('mousemove', drag, true); document.addEventListener('mouseup', stopDrag, true); handle.style.cursor = 'grabbing'; } function drag(e) { // 检查是否超过拖动阈值,避免误判为拖动 const dx = Math.abs(e.clientX - dragStartX); const dy = Math.abs(e.clientY - dragStartY); if (dx > DRAG_THRESHOLD || dy > DRAG_THRESHOLD) { isDragging = true; element.classList.add('dragging'); e.preventDefault(); e.stopPropagation(); // 计算新位置 const newX = e.clientX - offsetX; const newY = e.clientY - offsetY; const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const elementWidth = element.offsetWidth; const elementHeight = element.offsetHeight; // 边界限制 const boundedX = Math.max(0, Math.min(newX, viewportWidth - elementWidth)); const boundedY = Math.max(0, Math.min(newY, viewportHeight - elementHeight)); // 设置新位置 element.style.left = boundedX + 'px'; element.style.top = boundedY + 'px'; } } function stopDrag() { // 重置拖动状态 isDragging = false; element.classList.remove('dragging'); document.removeEventListener('mousemove', drag, true); document.removeEventListener('mouseup', stopDrag, true); handle.style.cursor = 'move'; } // 鼠标按下时启动拖动检测 handle.addEventListener('mousedown', startDrag); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址