您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Collects URLs from DuckDuckGo with optional site: filtering and rate limiting
// ==UserScript== // @name DuckDuckGo URL Collector // @namespace http://tampermonkey.net/ // @version 1.3 // @description Collects URLs from DuckDuckGo with optional site: filtering and rate limiting // @author Ghosty-Tongue // @match *://duckduckgo.com/* // @grant GM_notification // @license MIT // ==/UserScript== (function() { 'use strict'; const collectedUrls = new Set(); let isProcessing = false; let startTime, timerInterval; let targetSite = null; const searchForm = document.getElementById('search_form_input'); if (searchForm && searchForm.value.includes('site:')) { const match = searchForm.value.match(/site:([^\s]+)/); if (match) { targetSite = match[1].toLowerCase(); } } const banner = document.createElement('div'); Object.assign(banner.style, { position: 'fixed', top: '90px', right: '10px', zIndex: '10001', backgroundColor: 'rgba(255, 165, 0, 0.9)', color: 'white', padding: '10px', borderRadius: '5px', display: 'none' }); document.body.appendChild(banner); const style = document.createElement('style'); style.textContent = ` @keyframes rgbFlow { 0% { background-position: 0% 50%; } 100% { background-position: 100% 50%; } } `; document.head.appendChild(style); const timerDisplay = document.createElement('div'); Object.assign(timerDisplay.style, { position: 'fixed', top: '50px', right: '10px', zIndex: '10000', color: 'white', backgroundColor: 'rgba(0,0,0,0.7)', padding: '5px 10px', borderRadius: '5px', fontFamily: 'Arial, sans-serif', fontSize: '14px' }); document.body.appendChild(timerDisplay); function startTimer() { if (timerInterval) clearInterval(timerInterval); startTime = Date.now(); timerInterval = setInterval(updateTimer, 1000); timerDisplay.textContent = '0s'; } function updateTimer() { const elapsed = Math.floor((Date.now() - startTime) / 1000); timerDisplay.textContent = `${elapsed}s`; } function stopTimer() { clearInterval(timerInterval); const elapsed = Math.floor((Date.now() - startTime) / 1000); timerDisplay.textContent = `${elapsed}s (stopped)`; } function extractUrls() { const results = document.querySelectorAll('article[data-testid="result"]'); let newUrlsCount = 0; results.forEach(result => { const link = result.querySelector('a[data-testid="result-extras-url-link"]'); if (link) { const url = link.href; const urlDomain = new URL(url).hostname.toLowerCase(); if (targetSite) { if (!urlDomain.includes(targetSite)) return; } if (!collectedUrls.has(url)) { collectedUrls.add(url); newUrlsCount++; } } }); return newUrlsCount; } async function clickMoreResults() { isProcessing = true; btn.classList.add('processing'); let iteration = 1; let moreResultsButton; let batchCount = 0; do { if (!isProcessing) break; if (batchCount >= 420) { banner.textContent = 'Taking 15s break to avoid limits'; banner.style.display = 'block'; await new Promise(resolve => setTimeout(resolve, 15000)); banner.style.display = 'none'; batchCount = 0; } moreResultsButton = document.getElementById('more-results'); if (moreResultsButton) { moreResultsButton.click(); await new Promise(resolve => setTimeout(resolve, 2000)); batchCount += extractUrls(); iteration++; } } while (moreResultsButton && isProcessing); isProcessing = false; btn.classList.remove('processing'); GM_notification({ title: 'Collection Complete', text: `Saved ${collectedUrls.size} URLs`, timeout: 5000 }); saveUrls(); } function saveUrls() { const blob = new Blob([Array.from(collectedUrls).join('\n')], {type: 'text/plain'}); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'urls.txt'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); stopTimer(); } const btn = document.createElement('button'); btn.textContent = '🦆'; Object.assign(btn.style, { position: 'fixed', top: '10px', right: '10px', zIndex: '10000', padding: '12px 24px', background: 'linear-gradient(90deg, #ff0000, #00ff00, #0000ff, #ff0000)', backgroundSize: '300% 100%', animation: 'rgbFlow 5s linear infinite', color: 'white', border: 'none', borderRadius: '25px', cursor: 'pointer', fontFamily: 'Arial, sans-serif', fontWeight: 'bold', boxShadow: '0 4px 15px rgba(0,0,0,0.2)', transition: 'transform 0.2s, box-shadow 0.2s' }); btn.addEventListener('mouseover', () => { btn.style.transform = 'scale(1.05)'; btn.style.boxShadow = '0 6px 20px rgba(0,0,0,0.25)'; }); btn.addEventListener('mouseout', () => { btn.style.transform = 'scale(1)'; btn.style.boxShadow = '0 4px 15px rgba(0,0,0,0.2)'; }); btn.addEventListener('click', () => { if (!isProcessing) { collectedUrls.clear(); startTimer(); clickMoreResults(); } else { isProcessing = false; btn.classList.remove('processing'); banner.style.display = 'none'; stopTimer(); saveUrls(); } }); document.body.appendChild(btn); })();