Google Spam Filter

Clean up Google Search spam links

  1. // ==UserScript==
  2. // @name Google Spam Filter
  3. // @name:vi Dọn dẹp link rác Google Search
  4. // @namespace http://tampermonkey.net/
  5. // @version 1.6
  6. // @description Clean up Google Search spam links
  7. // @description:vi Dọn dẹp link rác trên Google Search
  8. // @author Yuusei
  9. // @icon https://www.google.com/favicon.ico
  10. // @match https://www.google.com/search*
  11. // @grant none
  12. // @license GPL-3.0-only
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. // options domains
  19. const spamDomains = new Set([
  20. '.fr',
  21. '.pl',
  22. ]);
  23.  
  24. // cache for URLs checked
  25. const urlCache = new Map();
  26. const CACHE_EXPIRY = 12 * 60 * 60 * 1000; // 12 hours
  27. const DEBOUNCE_DELAY = 250; // debounce time
  28. // check if url is spam
  29. function isSpamUrl(url) {
  30. if (!url) return false;
  31. const now = Date.now();
  32. // check cache first
  33. const cached = urlCache.get(url);
  34. if (cached) {
  35. if (now - cached.timestamp < CACHE_EXPIRY) {
  36. return cached.result;
  37. }
  38. urlCache.delete(url);
  39. }
  40.  
  41. const urlLower = url.toLowerCase();
  42. const isSpam = Array.from(spamDomains).some(domain => urlLower.includes(domain));
  43.  
  44. // save output to cache
  45. urlCache.set(url, {
  46. result: isSpam,
  47. timestamp: now
  48. });
  49. return isSpam;
  50. }
  51.  
  52. // debounce function to prevent calling too many times
  53. function debounce(func, wait) {
  54. let timeout;
  55. return function(...args) {
  56. clearTimeout(timeout);
  57. timeout = setTimeout(() => func.apply(this, args), wait);
  58. };
  59. }
  60.  
  61. // filter and hide spam results
  62. const filterSpamResults = debounce(() => {
  63. // select all search results
  64. const searchResults = document.querySelectorAll('#search .g, #rso .g');
  65. let spamCount = 0;
  66. const totalResults = searchResults.length;
  67. searchResults.forEach(result => {
  68. const elements = {
  69. link: result.querySelector('a'),
  70. cite: result.querySelector('cite'),
  71. title: result.querySelector('.oewGkc, .LC20lb'),
  72. snippet: result.querySelector('.VwiC3b')
  73. };
  74. const isSpam = elements.link && (
  75. isSpamUrl(elements.link.href) ||
  76. isSpamUrl(elements.cite?.textContent) ||
  77. isSpamUrl(elements.title?.textContent) ||
  78. isSpamUrl(elements.snippet?.textContent)
  79. );
  80.  
  81. if (isSpam) {
  82. result.style.display = 'none';
  83. spamCount++;
  84. }
  85. });
  86.  
  87. // show notification about the number of spam links filtered
  88. if (spamCount > 0) {
  89. const percentage = Math.round((spamCount / totalResults) * 100);
  90. console.log(`Cleaned ${spamCount}/${totalResults} spam results (${percentage}%)`);
  91. }
  92. }, DEBOUNCE_DELAY);
  93.  
  94. // run when page loaded
  95. window.addEventListener('DOMContentLoaded', filterSpamResults);
  96.  
  97. // observe content changes (Google dynamic loading)
  98. const observer = new MutationObserver((mutations) => {
  99. if (mutations.some(mutation => mutation.addedNodes.length > 0)) {
  100. filterSpamResults();
  101. }
  102. });
  103. observer.observe(document.documentElement, {
  104. childList: true,
  105. subtree: true
  106. });
  107. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址