您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
小红书自动检查粉丝关系,黑名单过滤,安全随机抽奖,CSV导出中奖名单!
// ==UserScript== // @name 小红书粉丝检查抽奖器 v4.4(抽奖版) // @namespace http://tampermonkey.net/ // @version 4.4 // @description 小红书自动检查粉丝关系,黑名单过滤,安全随机抽奖,CSV导出中奖名单! // @author Suzhiworkshops // @match https://www.xiaohongshu.com/explore/* // @grant GM_xmlhttpRequest // @connect xiaohongshu.com // ==/UserScript== (function () { 'use strict'; const CONFIG = { maxConcurrent: 5, delayBetweenBatches: 1000, baseUrl: 'https://www.xiaohongshu.com' }; let users = [], failedCount = 0, isProcessing = false; function createButton() { const button = document.createElement('button'); button.textContent = '📤 开始抽奖'; Object.assign(button.style, { position: 'fixed', top: '20px', right: '20px', padding: '10px 20px', backgroundColor: '#fe2c55', color: 'white', border: 'none', borderRadius: '20px', cursor: 'pointer', zIndex: 9999, fontSize: '14px', fontWeight: 'bold' }); button.onclick = async () => { if (isProcessing) return alert('处理中,请稍候'); isProcessing = true; button.disabled = true; button.textContent = '处理中...'; try { await start(); } catch (e) { addLog(`❌ 错误:${e.message}`); } finally { isProcessing = false; button.disabled = false; button.textContent = '📤 粉丝检测'; } }; document.body.appendChild(button); } async function getBlacklist() { const input = prompt('输入黑名单关键词(逗号分隔)', '广告,测试,抽奖'); return input ? input.split(',').map(k => k.trim()).filter(Boolean) : []; } async function start() { createPanel(); const blacklist = await getBlacklist(); addLog(`🔍 黑名单关键词:${blacklist.join(', ') || '无'}`); const nodes = document.querySelectorAll('.comment-item .name'); if (!nodes.length) return addLog('⚠️ 未找到用户,先加载评论'); const rawUsers = Array.from(nodes).map(el => ({ username: el.textContent.trim(), userId: el.getAttribute('data-user-id') || '未知', profileUrl: CONFIG.baseUrl + el.getAttribute('href'), isFan: false, checked: false })).filter(u => u.profileUrl); const seen = new Set(); const deduped = rawUsers.filter(u => seen.has(u.userId) ? false : seen.add(u.userId)); users = deduped.filter(u => { const hit = blacklist.find(k => u.username.includes(k)); if (hit) { addLog(`🚫 跳过:${u.username}(关键词:“${hit}”)`); return false; } return true; }); addLog(`🎯 待检测用户:${users.length}人`); await processBatches(users, CONFIG.maxConcurrent); finalize(); } async function processBatches(list, size) { for (let i = 0; i < list.length; i += size) { await Promise.all(list.slice(i, i + size).map(u => checkUser(u))); addLog(`📦 已检测:${Math.min(i + size, list.length)} / ${list.length}`); if (i + size < list.length) await sleep(CONFIG.delayBetweenBatches); } } async function checkUser(user) { return new Promise(resolve => { GM_xmlhttpRequest({ method: 'GET', url: user.profileUrl, headers: {'User-Agent': navigator.userAgent}, onload: res => { user.checked = true; user.isFan = /互相关注|回关/.test(res.responseText); addLog(`${user.isFan ? '❤️ 是粉丝' : '💔 非粉丝'}:${user.username}`); resolve(); }, onerror: err => { failedCount++; addLog(`❌ 失败:${user.username}`); resolve(); } }); }); } function finalize() { const fans = users.filter(u => u.checked && u.isFan); addLog(`✅ 完成:成功检测${fans.length}个粉丝,失败${failedCount}`); const count = Math.min(parseInt(prompt(`输入中奖人数(最多${fans.length}):`, '3')), fans.length); if (!count) return; const winners = secureShuffle(fans, count); addLog(`🏆 🎉 抽奖结果(${count}人):`); winners.forEach((u, i) => addLog(`第${i + 1}名 🎁 ${u.username}`)); exportCSV(winners, `中奖名单_${new Date().toISOString().slice(0, 10)}.csv`); } function secureShuffle(arr, count) { const res = [], used = new Set(); while (res.length < count && used.size < arr.length) { const r = crypto.getRandomValues(new Uint32Array(1))[0] % arr.length; if (!used.has(r)) used.add(r) && res.push(arr[r]); } return res; } function exportCSV(data, filename) { const csv = [ '\uFEFF用户名,用户ID,主页链接', ...data.map(u => `${u.username},${u.userId},${u.profileUrl}`) ].join('\n'); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename; link.textContent = '🎁 下载中奖名单'; Object.assign(link.style, { display: 'block', marginTop: '8px', background: '#27ae60', color: '#fff', textAlign: 'center', padding: '10px 0', borderRadius: '20px', textDecoration: 'none', fontSize: '14px' }); document.getElementById('xh-result-content').appendChild(link); } function createPanel() { if (document.getElementById('xh-result-panel')) return; const panel = document.createElement('div'); panel.id = 'xh-result-panel'; panel.style = 'position:fixed;top:70px;right:20px;width:340px;max-height:70vh;background:#fff;border-radius:12px;box-shadow:0 4px 18px rgba(0,0,0,0.1);overflow:auto;z-index:9999;font-family:sans-serif;color:#000'; panel.innerHTML = `<div style='padding:12px;font-weight:bold;border-bottom:1px solid #eee;font-size:15px;color:#000'>📋 粉丝检测日志</div><div id='xh-result-content' style='padding:12px;font-size:14px;color:#000;'></div>`; document.body.appendChild(panel); } function addLog(text) { const area = document.getElementById('xh-result-content'); if (!area) return; const p = document.createElement('p'); p.textContent = text; p.style.margin = '4px 0'; p.style.color = '#000'; if (/💔/.test(text)) p.style.color = '#888'; if (/❌|🚫/.test(text)) p.style.color = '#c0392b'; if (/✅|🎯|🏆/.test(text)) p.style.color = '#27ae60'; if (/⚠️/.test(text)) p.style.color = '#e67e22'; area.appendChild(p); area.scrollTop = area.scrollHeight; } function sleep(ms) { return new Promise(r => setTimeout(r, ms)); } createButton(); })();