// ==UserScript== // @name eh-v2 // @namespace http://tampermonkey.net/ // @version 1.1 // @description 采集页面数据并发送到后端 // @author Jack // @match *://*/* // @grant GM_xmlhttpRequest // ==/UserScript== (function() { 'use strict'; // 全局配置 - 请根据实际情况修改这些值 const BACKEND_IP = '127.0.0.1'; const BACKEND_PORT = '55830'; const BUTTON_LOCATION_SELECTOR = '#gd5 > p:nth-child(5)'; const DATA_LIST_SELECTOR = '#gdt a'; // 修改为a标签的选择器 const ALL_IMG_DATA = {}; // 用于储存每一页的图片url, 格式为 {"0001": "https://example001.jpg", "0002": "https://example002.jpg"}, 最高支持4位数至9999 const source = 'eh'; // 创建按钮 const button = document.createElement('button'); button.id = 'data-sender-button'; button.textContent = "send data"; button.style.position = "fixed"; button.style.top = "32%"; button.style.right = "1%"; button.style.transform = "translateY(-50%)"; button.style.padding = "3px 8px"; button.style.fontSize = "10px"; button.style.backgroundColor = "#007baf"; button.style.color = "#fff"; button.style.border = "none"; button.style.borderRadius = "5px"; button.style.cursor = "pointer"; button.style.zIndex = "10000"; // 添加到指定位置 const targetElement = document.querySelector(BUTTON_LOCATION_SELECTOR); if (targetElement) { targetElement.appendChild(button); } else { // 如果选择器找不到元素,默认添加到body document.body.appendChild(button); } // 从页面中提取图片的函数 function extractImagesFromPage(htmlContent) { const images = []; // 创建一个临时div来解析HTML const tempDiv = document.createElement('div'); tempDiv.innerHTML = htmlContent; if (DATA_LIST_SELECTOR) { const linkElements = tempDiv.querySelectorAll(DATA_LIST_SELECTOR); linkElements.forEach(link => { // 从a标签中获取href属性,这通常是图片页面链接 const href = link.href; if (href) { images.push(href); } }); } return images; } // 格式化数字为4位数 function formatNumber(num) { return num.toString().padStart(4, '0'); } // 获取基础URL(移除分页参数) function getBaseUrl(url) { // 使用正则表达式移除 p= 参数及其值 return url.replace(/([?&])p=\d+(&|$)/, (match, p1, p2) => { // 如果后面还有参数,保留&符号,否则保留空字符串 return p2 === '&' ? p1 : ''; }).replace(/[?&]$/, ''); // 移除末尾的?或& } // 构建分页URL function buildPageUrl(baseUrl, page) { if (page === 0) { // 第0页不需要p参数(首页) return baseUrl.includes('?') ? baseUrl : baseUrl; } else { // 其他页添加p参数 const separator = baseUrl.includes('?') ? '&' : '?'; return baseUrl + separator + `p=${page}`; } } // 发送数据到后端的函数 function sendDataToBackend(data) { console.log('准备发送的数据:', data); console.log('数据类型:', typeof data); console.log('字符串化后的数据:', JSON.stringify(data)); return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "POST", url: `http://${BACKEND_IP}:${BACKEND_PORT}/api/save_json`, headers: { "Content-Type": "application/json", }, data: JSON.stringify(data), onload: function(response) { console.log('后端响应状态:', response.status); console.log('后端响应内容:', response.responseText); if (response.status === 200) { resolve(response); } else { reject(new Error(`后端返回错误: ${response.status} - ${response.responseText}`)); } }, onerror: function(error) { reject(error); } }); }); } // 处理单个页面的函数(支持HTML字符串和当前页面) async function processPage(page, htmlContent = null) { let images = []; let hasNewImage = false; // 处理当前页(page = 0)的情况 if (page === 0 && htmlContent === null) { // 直接从当前DOM中提取图片 if (DATA_LIST_SELECTOR) { const linkElements = document.querySelectorAll(DATA_LIST_SELECTOR); linkElements.forEach(link => { const href = link.href; if (href) { images.push(href); } }); } } else { // 获取分页URL并请求 const baseUrl = getBaseUrl(window.location.href); const pageUrl = buildPageUrl(baseUrl, page); // 如果是当前页面(htmlContent是响应内容) if (htmlContent) { images = extractImagesFromPage(htmlContent); } else { // 请求远程页面 try { const response = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: pageUrl, headers: { "Referer": window.location.href, "Cookie": document.cookie }, onload: function(response) { resolve(response); }, onerror: function(error) { reject(error); } }); }); images = extractImagesFromPage(response.responseText); } catch (error) { console.error(`第${page}页采集失败:`, error); return false; } } } if (images.length === 0) { console.log(`第${page}页没有图片,可能是最后一页`); return false; } // 检查是否有重复图片并添加到总数据中 images.forEach(href => { const isDuplicate = Object.values(ALL_IMG_DATA).includes(href); if (!isDuplicate) { ALL_IMG_DATA[formatNumber(Object.keys(ALL_IMG_DATA).length + 1)] = href; hasNewImage = true; } }); console.log(`第${page}页采集完成,获取到${images.length}个图片链接,新增${hasNewImage ? '有新图片' : '全是重复图片'}`); return hasNewImage; } // 点击事件处理 button.addEventListener('click', async function() { // 1. 获取当前URL和title const currentUrl = window.location.href; const pageTitle = document.title; // 清空之前的图片数据 Object.keys(ALL_IMG_DATA).forEach(key => delete ALL_IMG_DATA[key]); // 获取当前页码(如果存在) const pageMatch = currentUrl.match(/[?&]p=(\d+)/); const currentPage = pageMatch ? parseInt(pageMatch[1]) : 0; console.log(`当前页码: ${currentPage}`); // 从第0页开始处理(包括当前页面) let shouldContinue = true; let page = 0; while (shouldContinue && page <= 100) { if (page === 0) { // 处理当前页(第0页),直接使用当前DOM const hasNewImages = await processPage(0, null); if (!hasNewImages && page > 0) { console.log(`第${page}页没有新图片,可能已到最后一页,停止采集`); shouldContinue = false; } } else { // 处理后续分页 const hasNewImages = await processPage(page); if (!hasNewImages) { console.log(`第${page}页没有新图片,可能已到最后一页,停止采集`); shouldContinue = false; } } // 如果图片数量达到上限也停止 if (Object.keys(ALL_IMG_DATA).length >= 2200) { console.log('图片数量达到上限2200,停止采集'); shouldContinue = false; } page++; } // 打包最终数据 const data = { url: currentUrl, title: pageTitle, source: source, imgs: ALL_IMG_DATA, totalImages: Object.keys(ALL_IMG_DATA).length }; // 显示结果并发送到后端 console.log('采集完成的所有数据:', data); console.log('后端地址:', BACKEND_IP + ':' + BACKEND_PORT); try { await sendDataToBackend(data); alert(`数据采集完成并已保存到后端!\n标题: ${pageTitle}\n总图片链接数量: ${Object.keys(ALL_IMG_DATA).length}`); } catch (error) { console.error('发送数据到后端失败:', error); alert(`数据采集完成但保存到后端失败!\n错误: ${error.message}\n请在控制台查看完整数据`); } }); })();