// ==UserScript== // @name 淘宝国补贴智能防封抢购助手 // @namespace http://tampermonkey.net/ // @version 3.6 // @description DOM点击+API请求双模式,修复启动问题,智能防封禁 // @author YourName // @match https://pages.tmall.com/* // @match https://pages.taobao.com/* // @match https://pages-fast.m.taobao.com/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_notification // @grant GM_log // @connect * // @require https://code.jquery.com/jquery-3.6.0.min.js // @run-at document-end // ==/UserScript== (function() { 'use strict'; class FixedSubsidyHelper { constructor() { this.config = { maxAttempts: 500, workers: [ { type: 'dom', enabled: true, weight: 1, delay: [2000, 5000] }, { type: 'api', enabled: true, weight: 2, delay: [1500, 4000] }, { type: 'dom', enabled: true, weight: 1, delay: [2500, 6000] }, { type: 'api', enabled: true, weight: 2, delay: [1800, 4500] } ], successKeywords: [ '领取成功', '抢到', '获得', '成功领取', '已领取', '恭喜', '抢券成功', '领取成功,已发放' ], failureKeywords: [ '已抢光', '活动结束', '来晚了', '抢完了', '库存不足', '活动已结束', '已售罄' ], banKeywords: [ '访问过于频繁', '请稍后再试', '验证码', '安全验证', '操作太快', '系统繁忙', '活动升级中' ] }; this.stats = { totalAttempts: 0, domAttempts: 0, apiAttempts: 0, success: false, startTime: Date.now(), running: false, discoveredAPIs: [], lastSuccessWorker: null, consecutiveFailures: 0, consecutiveEmpty: 0, coolDownUntil: 0, slowMode: false, banDetected: false }; this.isStopped = true; // 初始状态为停止 this.workerTimers = {}; console.log('🛠️ 脚本构造函数完成'); } async init() { console.log('🚀 开始初始化脚本...'); try { // 等待jQuery加载 await this.waitForjQuery(); console.log('✅ jQuery加载完成'); // 注入样式 this.injectStyles(); console.log('✅ 样式注入完成'); // 创建UI await this.createUI(); console.log('✅ UI创建完成'); // 加载统计数据 this.loadStats(); console.log('✅ 统计数据加载完成'); // 设置请求拦截 this.setupRequestInterception(); console.log('✅ 请求拦截设置完成'); // 分析页面结构 setTimeout(() => { this.analyzePageStructure(); this.discoverAPIs(); }, 3000); console.log('🎉 脚本初始化完成!'); this.showNotification('脚本初始化完成,可以开始抢购!'); } catch (error) { console.error('❌ 脚本初始化失败:', error); this.showNotification('脚本初始化失败,请刷新页面重试'); } } waitForjQuery() { return new Promise((resolve) => { if (window.jQuery) { resolve(); } else { const checkInterval = setInterval(() => { if (window.jQuery) { clearInterval(checkInterval); resolve(); } }, 100); // 10秒超时 setTimeout(() => { clearInterval(checkInterval); console.log('⚠️ jQuery加载超时,尝试继续'); resolve(); }, 10000); } }); } injectStyles() { const css = ` .fixed-helper-panel { position: fixed; top: 20px; right: 20px; background: rgba(255,255,255,0.98); border: 2px solid #ff5000; border-radius: 12px; padding: 15px; z-index: 10000; font-family: 'Microsoft YaHei', sans-serif; box-shadow: 0 6px 25px rgba(0,0,0,0.25); min-width: 420px; max-width: 500px; backdrop-filter: blur(12px); max-height: 80vh; overflow-y: auto; } .fixed-helper-title { color: #ff5000; font-weight: bold; margin-bottom: 12px; text-align: center; font-size: 16px; display: flex; align-items: center; justify-content: center; gap: 8px; } .fixed-helper-stats { font-size: 12px; margin: 6px 0; padding: 6px; background: #f8f8f8; border-radius: 5px; border-left: 3px solid #ff5000; } .fixed-helper-worker-stats { font-size: 11px; margin: 3px 0; padding: 4px 6px; background: #f0f0f0; border-radius: 3px; border-left: 2px solid #ccc; } .worker-dom { border-left-color: #00c800 !important; background: #f0fff0 !important; } .worker-api { border-left-color: #0066cc !important; background: #f0f8ff !important; } .fixed-helper-success { color: #00c800; font-weight: bold; } .fixed-helper-warning { color: #ff6b00; font-weight: bold; } .fixed-helper-danger { color: #ff4444; font-weight: bold; } .fixed-helper-btn { background: #ff5000; color: white; border: none; padding: 10px 15px; border-radius: 6px; cursor: pointer; margin: 5px; font-size: 13px; flex: 1; transition: all 0.3s; font-weight: bold; min-width: 80px; } .fixed-helper-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(255,80,0,0.3); } .fixed-helper-btn:active { transform: translateY(0); } .fixed-helper-btn:disabled { background: #ccc !important; cursor: not-allowed; transform: none; box-shadow: none; } .fixed-helper-btn.start { background: linear-gradient(135deg, #00c800, #00a800); } .fixed-helper-btn.start:hover:not(:disabled) { background: linear-gradient(135deg, #00a800, #008800); } .fixed-helper-btn.stop { background: linear-gradient(135deg, #666, #444); } .fixed-helper-btn.stop:hover:not(:disabled) { background: linear-gradient(135deg, #555, #333); } .fixed-helper-btns { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; justify-content: center; } .fixed-helper-status { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 6px; } .status-running { background: #00c800; animation: pulse 1s infinite; } .status-cooling { background: #0066cc; animation: pulse 2s infinite; } .status-banned { background: #ff4444; animation: pulse 0.5s infinite; } .status-stopped { background: #666; } @keyframes pulse { 0% { opacity: 1; transform: scale(1); } 50% { opacity: 0.7; transform: scale(1.1); } 100% { opacity: 1; transform: scale(1); } } .progress-bar { height: 6px; background: #eee; border-radius: 3px; margin: 8px 0; overflow: hidden; } .progress-fill { height: 100%; background: linear-gradient(90deg, #00c800, #00a800); border-radius: 3px; transition: width 0.3s; } .cooling .progress-fill { background: linear-gradient(90deg, #0066cc, #004499); } .banned .progress-fill { background: linear-gradient(90deg, #ff4444, #cc0000); } .api-list { max-height: 120px; overflow-y: auto; margin: 10px 0; padding: 8px; background: #f8f8f8; border-radius: 5px; font-size: 10px; border: 1px solid #e0e0e0; } .api-item { padding: 4px 6px; margin: 3px 0; background: white; border-radius: 3px; border-left: 3px solid #0066cc; word-break: break-all; font-family: monospace; } .window-tip { font-size: 11px; color: #666; margin-top: 12px; border-top: 1px solid #eee; padding-top: 10px; text-align: center; line-height: 1.4; } .debug-info { font-size: 10px; color: #888; background: #f5f5f5; padding: 5px; border-radius: 3px; margin-top: 5px; } `; const style = document.createElement('style'); style.textContent = css; document.head.appendChild(style); console.log('✅ CSS样式已注入'); } async createUI() { return new Promise((resolve) => { // 确保body元素存在 const checkBody = setInterval(() => { if (document.body) { clearInterval(checkBody); this.createPanel(); resolve(); } }, 100); // 5秒超时 setTimeout(() => { clearInterval(checkBody); console.log('⚠️ Body加载超时,尝试创建面板'); this.createPanel(); resolve(); }, 5000); }); } createPanel() { console.log('🛠️ 开始创建UI面板...'); // 移除可能存在的旧面板 const oldPanel = document.getElementById('fixed-helper-panel'); if (oldPanel) { oldPanel.remove(); console.log('🗑️ 移除旧面板'); } const panelHTML = `
🚀 淘宝国补贴助手
状态: 已停止
总尝试: 0
结果: 等待开始
🔍 发现的API: 0
正在检测API...
等待启动Worker...
💡 提示: 如果点击无反应,请刷新页面重试
📍 面板位置可拖动调整
初始化完成 | 等待用户操作
`; document.body.insertAdjacentHTML('beforeend', panelHTML); console.log('✅ UI面板已创建'); // 绑定事件 this.bindEvents(); this.updateWorkersUI(); // 添加拖动功能 this.makePanelDraggable(); } bindEvents() { console.log('🔗 绑定按钮事件...'); const startBtn = document.getElementById('fixed-start'); const stopBtn = document.getElementById('fixed-stop'); if (startBtn) { startBtn.onclick = () => { console.log('🎯 开始按钮被点击'); this.start(); }; console.log('✅ 开始按钮事件绑定成功'); } else { console.error('❌ 开始按钮未找到'); } if (stopBtn) { stopBtn.onclick = () => { console.log('⏹️ 停止按钮被点击'); this.stop(); }; console.log('✅ 停止按钮事件绑定成功'); } else { console.error('❌ 停止按钮未找到'); } this.updateDebugInfo('事件绑定完成'); } makePanelDraggable() { const panel = document.getElementById('fixed-helper-panel'); if (!panel) return; let isDragging = false; let startX, startY, initialX, initialY; panel.style.cursor = 'move'; panel.addEventListener('mousedown', (e) => { if (e.target.tagName === 'BUTTON') return; isDragging = true; startX = e.clientX; startY = e.clientY; initialX = panel.offsetLeft; initialY = panel.offsetTop; panel.style.transition = 'none'; document.body.style.userSelect = 'none'; e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; const deltaX = e.clientX - startX; const deltaY = e.clientY - startY; panel.style.left = (initialX + deltaX) + 'px'; panel.style.top = (initialY + deltaY) + 'px'; panel.style.right = 'auto'; }); document.addEventListener('mouseup', () => { isDragging = false; panel.style.transition = 'all 0.3s'; document.body.style.userSelect = ''; }); } updateDebugInfo(message) { const debugEl = document.getElementById('debug-info'); if (debugEl) { debugEl.textContent = `${new Date().toLocaleTimeString()} | ${message}`; } } start() { console.log('🚀 开始启动抢购流程...'); this.updateDebugInfo('启动中...'); if (this.stats.running) { console.log('⚠️ 已经在运行中'); this.updateDebugInfo('已在运行中'); return; } try { this.stats.running = true; this.isStopped = false; this.stats.success = false; this.stats.totalAttempts = 0; this.stats.domAttempts = 0; this.stats.apiAttempts = 0; this.stats.consecutiveFailures = 0; this.stats.consecutiveEmpty = 0; this.stats.startTime = Date.now(); this.stats.slowMode = false; this.stats.banDetected = false; console.log('✅ 状态重置完成'); // 更新UI状态 this.updateUI(); this.updateDebugInfo('状态已重置'); // 启动所有workers let startedWorkers = 0; this.config.workers.forEach((worker, index) => { if (worker.enabled) { this.startWorker(index + 1); startedWorkers++; } }); console.log(`✅ 启动了 ${startedWorkers} 个worker`); this.updateDebugInfo(`启动了 ${startedWorkers} 个worker`); this.showNotification('🚀 抢购已开始!持续监控中...'); } catch (error) { console.error('❌ 启动过程中出错:', error); this.updateDebugInfo(`启动错误: ${error.message}`); this.showNotification('启动失败,请查看控制台'); } } startWorker(workerId) { console.log(`👷 启动Worker ${workerId}`); const worker = this.config.workers[workerId - 1]; if (!worker) { console.error(`❌ Worker ${workerId} 配置不存在`); return; } // 清除可能存在的旧定时器 if (this.workerTimers[workerId]) { clearTimeout(this.workerTimers[workerId]); } const workerFunction = async () => { if (!this.stats.running || this.isStopped) { console.log(`⏹️ Worker ${workerId} 停止运行`); this.workerTimers[workerId] = null; return; } try { console.log(`🔧 Worker ${workerId} 执行任务 (${worker.type})`); if (worker.type === 'dom') { await this.domWorker(workerId); } else if (worker.type === 'api') { await this.apiWorker(workerId); } console.log(`✅ Worker ${workerId} 任务完成`); } catch (error) { console.error(`❌ Worker ${workerId} 执行错误:`, error); this.stats.consecutiveFailures++; } // 检查是否继续 if (this.shouldContinue()) { const baseDelay = this.randomDelay(worker.delay[0], worker.delay[1]); const weightedDelay = baseDelay / worker.weight; console.log(`⏳ Worker ${workerId} 等待 ${weightedDelay.toFixed(0)}ms`); this.workerTimers[workerId] = setTimeout(() => workerFunction(), weightedDelay); } else { console.log(`🛑 Worker ${workerId} 停止`); this.workerTimers[workerId] = null; this.updateUI(); } }; // 立即开始,不延迟 console.log(`🎬 Worker ${workerId} 立即开始`); workerFunction(); } async domWorker(workerId) { console.log(`🖱️ DOM Worker ${workerId} 寻找可点击元素`); const elements = this.findClickableElements(); console.log(`🔍 找到 ${elements.length} 个可点击元素`); if (elements.length > 0) { const element = elements[workerId % elements.length]; try { console.log(`🎯 DOM Worker ${workerId} 准备点击元素`); element.click(); this.stats.totalAttempts++; this.stats.domAttempts++; this.stats.consecutiveFailures = 0; this.stats.consecutiveEmpty = 0; console.log(`✅ DOM Worker ${workerId} 点击成功 (总尝试: ${this.stats.totalAttempts})`); this.updateDebugInfo(`DOM点击成功: ${this.stats.totalAttempts}次`); // 检查是否成功 setTimeout(() => this.checkSuccess(), 500); } catch (error) { console.log(`❌ DOM Worker ${workerId} 点击失败:`, error); this.stats.consecutiveFailures++; } } else { this.stats.totalAttempts++; this.stats.consecutiveEmpty++; console.log(`⚠️ DOM Worker ${workerId} 未找到可点击元素 (连续${this.stats.consecutiveEmpty}次)`); this.updateDebugInfo(`未找到元素: ${this.stats.consecutiveEmpty}次`); } this.updateUI(); } async apiWorker(workerId) { console.log(`🌐 API Worker ${workerId} 准备请求`); if (this.stats.discoveredAPIs.length === 0) { this.stats.totalAttempts++; console.log(`⚠️ API Worker ${workerId} 暂无可用API`); this.updateDebugInfo('暂无API可用'); return; } const api = this.stats.discoveredAPIs[workerId % this.stats.discoveredAPIs.length]; if (!api) return; try { console.log(`📡 API Worker ${workerId} 请求: ${api.url}`); await this.makeAPIRequest(api, workerId); this.stats.totalAttempts++; this.stats.apiAttempts++; console.log(`✅ API Worker ${workerId} 请求完成 (总尝试: ${this.stats.totalAttempts})`); this.updateDebugInfo(`API请求完成: ${this.stats.totalAttempts}次`); } catch (error) { console.log(`❌ API Worker ${workerId} 请求失败:`, error); this.stats.totalAttempts++; this.stats.consecutiveFailures++; this.updateDebugInfo(`API请求失败: ${error.message}`); } this.updateUI(); } findClickableElements() { const elements = []; const buttonTexts = ['立即领取', '点击领取', '领取补贴', '马上领取']; // 方法1: 通过文本内容查找 buttonTexts.forEach(text => { const xpath = `//*[contains(text(), '${text}')]`; try { const result = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (let i = 0; i < result.snapshotLength; i++) { const element = result.snapshotItem(i); if (element && this.isElementVisible(element)) { elements.push(element); } } } catch (e) { console.log('XPath查询失败:', e); } }); // 方法2: 通过CSS类名查找 const cssSelectors = ['.btn', '.button', '[class*="btn"]', '[class*="button"]', 'button']; cssSelectors.forEach(selector => { try { document.querySelectorAll(selector).forEach(element => { if (element && this.isElementVisible(element) && !elements.includes(element)) { const text = element.textContent || ''; if (buttonTexts.some(btnText => text.includes(btnText))) { elements.push(element); } } }); } catch (e) { console.log('CSS选择器查询失败:', e); } }); console.log(`🎯 最终找到 ${elements.length} 个可点击元素`); return elements; } isElementVisible(el) { if (!el) return false; try { const style = window.getComputedStyle(el); return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'; } catch (e) { return false; } } makeAPIRequest(api, workerId) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: api.method || 'GET', url: api.url, data: api.data, headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest' }, onload: (response) => { console.log(`📦 API Worker ${workerId} 响应状态: ${response.status}`); resolve(response); }, onerror: (error) => { reject(error); }, timeout: 10000 }); }); } checkSuccess() { const pageText = document.body.textContent; const hasSuccess = this.config.successKeywords.some(keyword => pageText.includes(keyword) ); if (hasSuccess && !this.stats.success) { this.stats.success = true; console.log('🎉 检测到抢购成功!'); this.updateDebugInfo('抢购成功!'); this.showNotification('🎉 抢购成功!恭喜!'); this.stop(); } return hasSuccess; } shouldContinue() { if (this.isStopped) return false; if (this.stats.success) return false; if (this.stats.totalAttempts >= this.config.maxAttempts) { console.log('🛑 达到最大尝试次数'); this.showNotification('⏹️ 达到最大尝试次数,停止抢购'); return false; } return true; } stop() { console.log('🛑 停止所有worker'); this.updateDebugInfo('停止中...'); this.stats.running = false; this.isStopped = true; // 清除所有定时器 Object.values(this.workerTimers).forEach(timer => { if (timer) clearTimeout(timer); }); this.workerTimers = {}; this.updateUI(); this.saveStats(); console.log('✅ 已完全停止'); this.updateDebugInfo('已停止'); if (this.stats.success) { this.showNotification('✅ 抢购成功!任务完成'); } else { this.showNotification('⏹️ 抢购已停止'); } } updateUI() { // 更新状态文本 const statusText = document.getElementById('status-text'); const attemptsText = document.getElementById('attempts-text'); const successText = document.getElementById('success-text'); const progressBar = document.getElementById('fixed-progress'); const startBtn = document.getElementById('fixed-start'); const stopBtn = document.getElementById('fixed-stop'); if (statusText) { statusText.textContent = this.stats.running ? '运行中' : '已停止'; } if (attemptsText) { attemptsText.textContent = this.stats.totalAttempts.toString(); } if (successText) { successText.textContent = this.stats.success ? '✅ 成功' : this.stats.running ? '进行中...' : '等待开始'; successText.className = this.stats.success ? 'fixed-helper-success' : ''; } if (progressBar) { const progress = Math.min(100, (this.stats.totalAttempts / this.config.maxAttempts) * 100); progressBar.style.width = `${progress}%`; } if (startBtn) { startBtn.disabled = this.stats.running; } if (stopBtn) { stopBtn.disabled = !this.stats.running; } // 更新状态指示器 this.updateStatusIndicator(); } updateStatusIndicator() { const statusEl = document.querySelector('#fixed-stats .fixed-helper-status'); if (!statusEl) return; statusEl.className = 'fixed-helper-status '; if (this.stats.running) { statusEl.classList.add('status-running'); } else { statusEl.classList.add('status-stopped'); } } updateWorkersUI() { const container = document.getElementById('fixed-workers-container'); if (!container) return; let workersHTML = ''; this.config.workers.forEach((worker, index) => { const workerId = index + 1; workersHTML += `
Worker ${workerId} (${worker.type.toUpperCase()}) | 权重: ${worker.weight}
`; }); container.innerHTML = workersHTML; } updateAPIListUI() { const apiCount = document.getElementById('api-count'); const apiList = document.getElementById('api-list'); if (apiCount) { apiCount.textContent = this.stats.discoveredAPIs.length.toString(); } if (apiList) { if (this.stats.discoveredAPIs.length === 0) { apiList.innerHTML = '
尚未发现API,请等待...
'; } else { let apiHTML = ''; this.stats.discoveredAPIs.slice(0, 3).forEach(api => { apiHTML += `
${api.method}
${api.url.substring(0, 50)}...
`; }); apiList.innerHTML = apiHTML; } } } setupRequestInterception() { console.log('🔍 设置请求拦截...'); // 简化的请求拦截,实际使用时需要更复杂的实现 } analyzePageStructure() { console.log('📄 分析页面结构...'); // 简化的页面分析 } discoverAPIs() { console.log('🌐 发现API...'); // 模拟发现一些API setTimeout(() => { this.stats.discoveredAPIs = [ { url: 'https://example.com/api/subsidy', method: 'POST', data: '' }, { url: 'https://example.com/api/coupon', method: 'GET', data: '' } ]; this.updateAPIListUI(); console.log('✅ 模拟API发现完成'); }, 2000); } showNotification(message) { console.log('💬 通知:', message); if (typeof GM_notification !== 'undefined') { GM_notification({ text: message, title: '淘宝抢购助手', timeout: 3000 }); } else { // 备用通知方式 const notification = document.createElement('div'); notification.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0,0,0,0.8); color: white; padding: 20px; border-radius: 10px; z-index: 10001; font-size: 16px; `; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 3000); } } loadStats() { console.log('📊 加载统计数据...'); // 简化的统计加载 } saveStats() { console.log('💾 保存统计数据...'); // 简化的统计保存 } randomDelay(min, max) { return Math.random() * (max - min) + min; } } // 主初始化函数 async function initializeScript() { console.log('🎬 开始初始化淘宝抢购助手...'); // 等待页面基本加载完成 if (document.readyState === 'loading') { await new Promise(resolve => { document.addEventListener('DOMContentLoaded', resolve); }); } // 额外等待确保完全加载 await new Promise(resolve => setTimeout(resolve, 1000)); try { const helper = new FixedSubsidyHelper(); await helper.init(); // 保存实例到全局,便于调试 window.subsidyHelper = helper; console.log('✅ 脚本初始化完成,可以通过 window.subsidyHelper 访问实例'); } catch (error) { console.error('❌ 脚本初始化失败:', error); // 显示错误信息 const errorDiv = document.createElement('div'); errorDiv.style.cssText = ` position: fixed; top: 10px; left: 10px; background: #ff4444; color: white; padding: 10px; border-radius: 5px; z-index: 10000; font-family: Arial; `; errorDiv.innerHTML = ` 脚本初始化失败
错误: ${error.message}
请刷新页面重试或查看控制台 `; document.body.appendChild(errorDiv); } } // 启动脚本 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initializeScript); } else { initializeScript(); } })();