Bing Human Search

Ricerche umanizzate senza scrolling

  1. // ==UserScript==
  2. // @name Bing Human Search
  3. // @namespace http://tampermonkey.net/
  4. // @version 5.3
  5. // @description Ricerche umanizzate senza scrolling
  6. // @author Nayila Yassin
  7. // @license MIT
  8. // @match https://www.bing.com/*
  9. // @grant GM_xmlhttpRequest
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // @grant GM_addStyle
  13. // @connect api.datamuse.com
  14. // @connect random-word-api.herokuapp.com
  15. // ==/UserScript==
  16. (function() {
  17. 'use strict';
  18.  
  19. const STATE_KEY = 'BingHumanSearch_State';
  20. const WORD_CACHE_KEY = 'BingHumanSearch_Words';
  21.  
  22. // Configurazione aggiornata (tempo ridotto)
  23. const config = {
  24. typing: {
  25. min: 150, // Minimo tempo per digitare un carattere (ms)
  26. max: 500, // Massimo tempo per digitare un carattere (ms)
  27. errorRate: 0.15, // Probabilità di errore di battitura
  28. correctionProbability: 0.2 // Probabilità di correzione dell'errore
  29. },
  30. timing: {
  31. // 🔁 Tempo tra una ricerca e l'altra (15-30 secondi)
  32. searchDelay: { min: 15000, max: 30000 }, // Modificato da originale (60s-120s)
  33.  
  34. // ⏱️ Tempo di caricamento risultati (6-12 secondi)
  35. resultLoad: { min: 6000, max: 12000 },
  36.  
  37. // 🕵️ Tempo massimo di attesa per gli elementi (15 secondi)
  38. elementWait: { max: 15000, interval: 500 },
  39.  
  40. // 📜 Configurazione dello scroll
  41. scrollStep: { min: 300, max: 500 }, // Altezza singolo scroll (px)
  42. scrollPause: { min: 500, max: 1500 }, // Pausa tra scroll consecutivi (ms)
  43. scrollCount: { min: 2, max: 4 } // Numero di scroll effettuati
  44. }
  45. };
  46.  
  47. let isRunning = GM_getValue(STATE_KEY, false);
  48. let wordCache = GM_getValue(WORD_CACHE_KEY, []);
  49. let controlPanel;
  50.  
  51. // Stili CSS globali
  52. GM_addStyle(`
  53. .bhs-control-panel {
  54. position: fixed;
  55. bottom: 25px;
  56. right: 25px;
  57. z-index: 99999;
  58. background: rgba(255,255,255,0.95);
  59. border-radius: 15px;
  60. padding: 15px;
  61. box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  62. border: 1px solid #e0e0e0;
  63. min-width: 180px;
  64. font-family: 'Segoe UI', system-ui;
  65. }
  66. .bhs-button {
  67. background: ${isRunning ? '#e74c3c' : '#2ecc71'};
  68. color: white;
  69. border: none;
  70. padding: 12px 20px;
  71. border-radius: 8px;
  72. cursor: pointer;
  73. width: 100%;
  74. transition: all 0.25s ease;
  75. font-weight: 600;
  76. text-transform: uppercase;
  77. letter-spacing: 0.5px;
  78. }
  79. .bhs-button:hover {
  80. opacity: 0.9;
  81. transform: translateY(-1px);
  82. }
  83. .bhs-status {
  84. margin-top: 12px;
  85. font-size: 0.9em;
  86. color: #555;
  87. text-align: center;
  88. }
  89. `);
  90.  
  91. async function init() {
  92. createControlPanel();
  93. refreshWordCache();
  94. if(isRunning) startAutomation();
  95. }
  96.  
  97. function createControlPanel() {
  98. controlPanel = document.createElement('div');
  99. controlPanel.className = 'bhs-control-panel';
  100. const btn = document.createElement('button');
  101. btn.className = 'bhs-button';
  102. btn.textContent = isRunning ? '⏹ STOP' : '▶ START';
  103. btn.onclick = toggleAutomation;
  104. const status = document.createElement('div');
  105. status.className = 'bhs-status';
  106. status.textContent = 'Status: ' + (isRunning ? 'Active 🔄' : 'Paused ⏸');
  107. controlPanel.append(btn, status);
  108. document.body.appendChild(controlPanel);
  109. }
  110.  
  111. function updateStatus(text) {
  112. const status = controlPanel.querySelector('.bhs-status');
  113. if(status) status.textContent = `Status: ${text}`;
  114. }
  115.  
  116. function toggleAutomation() {
  117. isRunning = !isRunning;
  118. GM_setValue(STATE_KEY, isRunning);
  119. refreshControlPanel();
  120. if(isRunning) {
  121. startAutomation();
  122. } else {
  123. updateStatus('Paused ⏸');
  124. }
  125. }
  126.  
  127. function refreshControlPanel() {
  128. const btn = controlPanel.querySelector('.bhs-button');
  129. if(btn) {
  130. btn.textContent = isRunning ? '⏹ STOP' : '▶ START';
  131. btn.style.backgroundColor = isRunning ? '#e74c3c' : '#2ecc71';
  132. }
  133. }
  134.  
  135. async function refreshWordCache() {
  136. if(wordCache.length > 20) return;
  137. try {
  138. const source = config.wordSources[Math.floor(Math.random() * config.wordSources.length)];
  139. const words = await fetchJSON(source);
  140. if(Array.isArray(words)) {
  141. wordCache = words.slice(0, 50).map(w => w.word || w);
  142. GM_setValue(WORD_CACHE_KEY, wordCache);
  143. }
  144. } catch(e) {
  145. console.warn('Failed to refresh word cache, using fallback');
  146. wordCache = ['test', 'search', 'demo', 'example', 'hello'];
  147. }
  148. }
  149.  
  150. function getRandomWord() {
  151. return wordCache.length > 0
  152. ? wordCache.splice(Math.floor(Math.random() * wordCache.length), 1)[0]
  153. : 'search';
  154. }
  155.  
  156. async function waitForElement(selector, timeout = config.timing.elementWait.max) {
  157. return new Promise((resolve, reject) => {
  158. const start = Date.now();
  159. const check = setInterval(() => {
  160. const el = document.querySelector(selector);
  161. if(el) {
  162. clearInterval(check);
  163. resolve(el);
  164. } else if(Date.now() - start > timeout) {
  165. clearInterval(check);
  166. reject(new Error('Element not found'));
  167. }
  168. }, config.timing.elementWait.interval);
  169. });
  170. }
  171.  
  172. async function humanType(text, element) {
  173. let currentText = '';
  174. for(const char of text) {
  175. if(!isRunning) break;
  176. if(Math.random() < config.typing.errorRate) {
  177. const fakeChar = String.fromCharCode(97 + Math.floor(Math.random() * 26));
  178. currentText += fakeChar;
  179. await updateElement(element, currentText);
  180. if(Math.random() < config.typing.correctionProbability) {
  181. currentText = currentText.slice(0, -1);
  182. await updateElement(element, currentText);
  183. await randomDelay(50, 150);
  184. }
  185. }
  186. currentText += char;
  187. await updateElement(element, currentText);
  188. await randomDelay(config.typing.min, config.typing.max);
  189. }
  190. }
  191.  
  192. async function updateElement(element, value) {
  193. element.value = value;
  194. element.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
  195. element.dispatchEvent(new Event('change', { bubbles: true }));
  196. }
  197.  
  198. async function smoothScrollDown() {
  199. const scrollCount = Math.floor(Math.random() *
  200. (config.timing.scrollCount.max - config.timing.scrollCount.min + 1)) +
  201. config.timing.scrollCount.min;
  202.  
  203. for(let i = 0; i < scrollCount && isRunning; i++) {
  204. const scrollAmount = Math.floor(Math.random() *
  205. (config.timing.scrollStep.max - config.timing.scrollStep.min + 1)) +
  206. config.timing.scrollStep.min;
  207.  
  208. window.scrollBy({
  209. top: scrollAmount,
  210. left: 0,
  211. behavior: 'smooth'
  212. });
  213.  
  214. await randomDelay(config.timing.scrollPause.min, config.timing.scrollPause.max);
  215. }
  216. }
  217.  
  218. async function performSearch() {
  219. try {
  220. updateStatus('Starting search... ⏳');
  221. const searchBox = await waitForElement('input[name="q"], textarea[name="q"]');
  222. searchBox.value = '';
  223. searchBox.focus();
  224. await randomDelay(500, 1200);
  225. const word = getRandomWord();
  226. updateStatus(`Typing: ${word} ⌨️`);
  227. await humanType(word, searchBox);
  228. updateStatus('Submitting form... 📨');
  229. searchBox.dispatchEvent(new KeyboardEvent('keydown', {
  230. key: 'Enter',
  231. code: 'Enter',
  232. keyCode: 13,
  233. bubbles: true,
  234. composed: true
  235. }));
  236. updateStatus('Loading results... ⏳');
  237. await waitForElement('#b_results');
  238. await randomDelay(
  239. config.timing.resultLoad.min,
  240. config.timing.resultLoad.max
  241. );
  242.  
  243. // Nuovo scroll aggiunto qui
  244. updateStatus('Scrolling results... 📜');
  245. await smoothScrollDown();
  246.  
  247. updateStatus('Waiting next cycle... ⏳');
  248. await randomDelay(
  249. config.timing.searchDelay.min,
  250. config.timing.searchDelay.max
  251. );
  252. if(isRunning) performSearch();
  253. } catch(error) {
  254. console.error('Automation error:', error);
  255. updateStatus(`Error: ${error.message} ⚠️`);
  256. if(isRunning) setTimeout(performSearch, 5000);
  257. }
  258. }
  259.  
  260. function startAutomation() {
  261. if(!isRunning) return;
  262. updateStatus('Initializing... ⚡');
  263. performSearch().catch(e => console.error('Fatal error:', e));
  264. }
  265.  
  266. function randomDelay(min, max) {
  267. return new Promise(r => setTimeout(r, Math.random() * (max - min) + min));
  268. }
  269.  
  270. function fetchJSON(url) {
  271. return new Promise((resolve, reject) => {
  272. GM_xmlhttpRequest({
  273. method: 'GET',
  274. url,
  275. onload: r => resolve(JSON.parse(r.responseText)),
  276. onerror: reject
  277. });
  278. });
  279. }
  280.  
  281. window.addEventListener('load', init, false);
  282. })();