diff --git a/Tampermonkey/eh.js b/Tampermonkey/eh.js new file mode 100644 index 0000000..dc19c63 --- /dev/null +++ b/Tampermonkey/eh.js @@ -0,0 +1,261 @@ +// ==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请在控制台查看完整数据`); + } + }); +})(); \ No newline at end of file