Greasy Fork镜像 支持简体中文。

搜索引擎官网净化器-增强版

精准识别官网/智能屏蔽虚假结果(支持百度/谷歌/必应)

目前為 2025-03-31 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name 搜索引擎官网净化器-增强版
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.4
  5. // @description 精准识别官网/智能屏蔽虚假结果(支持百度/谷歌/必应)
  6. // @author AI助手优化版
  7. // @license MIT
  8. // @match *://www.baidu.com/*
  9. // @match *://www.google.com/*
  10. // @match *://www.bing.com/*
  11. // @grant GM_addStyle
  12. // @grant GM.getValue
  13. // @grant GM.setValue
  14. // @grant GM.registerMenuCommand
  15. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
  16. // @noframes
  17. // ==/UserScript==
  18.  
  19. (function() {
  20. 'use strict';
  21.  
  22. // 增强视觉样式
  23. GM_addStyle(`
  24. .official-site-mark {
  25. background: linear-gradient(135deg, #2196F3 0%, #1976D2 100%) !important;
  26. border-radius: 12px;
  27. padding: 2px 8px;
  28. color: white;
  29. font-size: 12px;
  30. margin-left: 8px;
  31. position: relative;
  32. top: -1px;
  33. animation: popIn 0.3s ease;
  34. }
  35. @keyframes popIn {
  36. 0% { transform: scale(0); }
  37. 90% { transform: scale(1.1); }
  38. 100% { transform: scale(1); }
  39. }
  40. .dangerous-result {
  41. position: relative;
  42. opacity: 0.3;
  43. transition: opacity 0.3s;
  44. }
  45. .dangerous-result::after {
  46. content: "⚠️ 危险结果已模糊处理";
  47. position: absolute;
  48. top: 50%;
  49. left: 50%;
  50. transform: translate(-50%,-50%);
  51. color: #d32f2f;
  52. font-weight: bold;
  53. background: rgba(255,255,255,0.9);
  54. padding: 8px 16px;
  55. border-radius: 4px;
  56. box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  57. }
  58. `);
  59.  
  60. // 动态配置中心
  61. const SearchEngineConfig = {
  62. 'www.baidu.com': {
  63. selectors: {
  64. container: '#content_left',
  65. results: '.c-container, .result-op, [mu]',
  66. title: 'h3.t, h3 a',
  67. officialMark: [
  68. '.c-icon-certified', // 百度官方认证图标
  69. { type: 'text', pattern: /官网$/ },
  70. { type: 'attribute', selector: '[data-landmark="official"]' }
  71. ],
  72. dangerMark: [
  73. '.c-tips-icon-warning', // 百度风险提示图标
  74. { type: 'text', pattern: /(彩票|网赚|代购|刷单)/ }
  75. ]
  76. },
  77. dangerDomains: [
  78. /\.(xyz|top|loan|tk|ml)/i,
  79. /(wangzhan|seo|baidu\.zhuanlan)/i
  80. ],
  81. officialDomains: [
  82. /\.(gov|edu)\.cn$/,
  83. /(baidu|alibaba|tencent|jd)\.com$/
  84. ]
  85. },
  86. 'www.google.com': {
  87. selectors: {
  88. container: '#search',
  89. results: '.g:not(.ULSxyf)',
  90. title: 'h3, [role="heading"]',
  91. officialMark: [
  92. '.VuuXrf', // Google认证标记
  93. { type: 'text', pattern: / - Official Site$/i },
  94. { type: 'attribute', selector: '[aria-label="Verified"]' }
  95. ],
  96. dangerMark: [
  97. '.iDjcJe[aria-label="Warning"]', // Google危险提示
  98. { type: 'text', pattern: /(casino|porn|pharmacy)/i }
  99. ]
  100. },
  101. dangerDomains: [
  102. /\.(xyz|top|bid|loan)/i,
  103. /(freevpn|cheapdrugs|fake)/i
  104. ],
  105. officialDomains: [
  106. /\.(gov|edu|mil)$/,
  107. /(google|microsoft|apple)\.com$/
  108. ]
  109. },
  110. 'www.bing.com': {
  111. selectors: {
  112. container: '#b_results',
  113. results: '.b_algo',
  114. title: 'h2 > a',
  115. officialMark: [
  116. '[aria-label="官方站点"]',
  117. { type: 'text', pattern: /Official Site/i }
  118. ],
  119. dangerMark: [
  120. '.b_attribution > .b_dotext[href*="danger"]',
  121. { type: 'text', pattern: /(赌博|诈骗)/i }
  122. ]
  123. },
  124. dangerDomains: [
  125. /\.(stream|gq|cf)/i,
  126. /(poker|bitcoin)/i
  127. ],
  128. officialDomains: [
  129. /\.(gov|edu)/i,
  130. /(microsoft|bing)\.com$/i
  131. ]
  132. }
  133. };
  134.  
  135. class SearchGuard {
  136. constructor() {
  137. this.engine = location.hostname;
  138. this.config = SearchEngineConfig[this.engine];
  139. if (!this.config) return;
  140.  
  141. this.initState();
  142. this.enhanceUI();
  143. this.setupObservers();
  144. }
  145.  
  146. async initState() {
  147. this.enabled = await GM.getValue('searchGuardEnabled', true);
  148. this.debugMode = await GM.getValue('debugMode', false);
  149. this.log('初始化完成');
  150. }
  151.  
  152. log(...args) {
  153. if (this.debugMode) console.log('[SearchGuard]', ...args);
  154. }
  155.  
  156. enhanceUI() {
  157. // 添加调试面板
  158. const panel = document.createElement('div');
  159. panel.innerHTML = `
  160. <div style="position:fixed;top:20px;right:20px;background:#fff;
  161. padding:15px;border-radius:8px;box-shadow:0 2px 12px rgba(0,0,0,0.1);
  162. z-index:9999;font-family:Arial;">
  163. <h3 style="margin:0 0 10px;font-size:15px;">🔍 搜索防护</h3>
  164. <label style="display:flex;align-items:center;gap:8px;margin:6px 0;">
  165. <input type="checkbox" ${this.enabled ? 'checked' : ''}>
  166. <span>启用智能过滤</span>
  167. </label>
  168. <button style="margin-top:8px;padding:4px 8px;"
  169. onclick="document.dispatchEvent(new Event('searchGuardRefresh'))">
  170. 立即刷新结果
  171. </button>
  172. </div>
  173. `;
  174. document.body.appendChild(panel);
  175. panel.querySelector('input').addEventListener('change', e => {
  176. this.enabled = e.target.checked;
  177. GM.setValue('searchGuardEnabled', this.enabled);
  178. this.processAllResults();
  179. });
  180. }
  181.  
  182. setupObservers() {
  183. // 双保险监听:MutationObserver + 轮询检查
  184. const mainObserver = new MutationObserver(() => this.processAllResults());
  185. const container = document.querySelector(this.config.selectors.container);
  186. if (container) mainObserver.observe(container, { childList: true, subtree: true });
  187.  
  188. // 定时检查DOM变化(应对动态加载)
  189. setInterval(() => this.processAllResults(), 2000);
  190.  
  191. // 自定义刷新事件
  192. document.addEventListener('searchGuardRefresh', () => this.processAllResults());
  193. }
  194.  
  195. processAllResults() {
  196. if (!this.enabled) return;
  197. $(this.config.selectors.results).each((i, el) => {
  198. if (el.dataset.processed) return;
  199. this.analyzeResult(el);
  200. el.dataset.processed = true;
  201. });
  202. }
  203.  
  204. analyzeResult(element) {
  205. const url = this.getResultUrl(element);
  206. if (!url) return;
  207.  
  208. // 多重检测逻辑
  209. const isOfficial = this.checkOfficial(element, url);
  210. const isDangerous = this.checkDangerous(element, url);
  211.  
  212. if (isDangerous) {
  213. this.markAsDangerous(element);
  214. } else if (isOfficial) {
  215. this.markAsOfficial(element);
  216. }
  217. }
  218.  
  219. getResultUrl(element) {
  220. const link = element.querySelector(this.config.selectors.title)?.href;
  221. try {
  222. return new URL(link).hostname;
  223. } catch {
  224. return null;
  225. }
  226. }
  227.  
  228. checkOfficial(element, url) {
  229. // 特征检测 + 域名白名单
  230. return this.config.selectors.officialMark.some(marker => {
  231. if (typeof marker === 'string') {
  232. return element.querySelector(marker) !== null;
  233. }
  234. switch (marker.type) {
  235. case 'text':
  236. return marker.pattern.test(element.textContent);
  237. case 'attribute':
  238. return element.querySelector(marker.selector) !== null;
  239. default:
  240. return false;
  241. }
  242. }) || this.config.officialDomains.some(domain => domain.test(url));
  243. }
  244.  
  245. checkDangerous(element, url) {
  246. // 风险特征 + 危险域名
  247. return this.config.selectors.dangerMark.some(marker => {
  248. if (typeof marker === 'string') {
  249. return element.querySelector(marker) !== null;
  250. }
  251. switch (marker.type) {
  252. case 'text':
  253. return marker.pattern.test(element.textContent);
  254. case 'attribute':
  255. return element.querySelector(marker.selector) !== null;
  256. default:
  257. return false;
  258. }
  259. }) || this.config.dangerDomains.some(domain => domain.test(url));
  260. }
  261.  
  262. markAsOfficial(element) {
  263. const title = element.querySelector(this.config.selectors.title);
  264. if (!title || title.querySelector('.official-site-mark')) return;
  265.  
  266. const mark = document.createElement('span');
  267. mark.className = 'official-site-mark';
  268. mark.textContent = {
  269. 'www.baidu.com': '官方认证',
  270. 'www.google.com': 'Verified',
  271. 'www.bing.com': 'Official'
  272. }[this.engine];
  273. title.appendChild(mark);
  274. }
  275.  
  276. markAsDangerous(element) {
  277. element.classList.add('dangerous-result');
  278. element.querySelector('a')?.addEventListener('click', e => {
  279. e.preventDefault();
  280. alert('访问此网站可能存在风险!');
  281. });
  282. }
  283. }
  284.  
  285. // 启动防护(带错误恢复机制)
  286. let guard;
  287. function initGuard() {
  288. try {
  289. guard = new SearchGuard();
  290. } catch (error) {
  291. console.error('[SearchGuard] 初始化失败,2秒后重试:', error);
  292. setTimeout(initGuard, 2000);
  293. }
  294. }
  295. setTimeout(initGuard, 1000);
  296.  
  297. })();

QingJ © 2025

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