使用油猴脚本去除浏览器搜索的URL后缀,减少广告

任务背景

今天碰到了一件事,我在浏览器里搜索"adobe",它显示的URL是

https://www.bing.com/search?qs=HS&pq=adobe&sk=CSYN1UAS7MT2FT1LT5UT2CT1&sc=22-5&pglt=419&q=adobe&cvid=16277c9e0b644d67b1b6e44de18b1536&gs_lcrp=EgRlZGdlKgYIABAAGEAyBggAEAAYQDIGCAEQLhhAMgYIAhAuGEAyBggDEC4YQDIGCAQQRRg8MgYIBRBFGDwyBggGEEUYPDIGCAcQRRg8MgYICBBFGEHSAQg1MjcwajBqMagCALACAA&FORM=ANNTA1&PC=U531

通过对比分析和查阅资料,我发现它其实用于搜索的只有


https://www.bing.com/search?q=adobe

后面这一大串码可能是运营商给你的营销ID,通过这个链接他们能够获得广告分成。

针对这个问题,笔者借助AI,写一个完整的Tampermonkey脚本来避免。 并且希望将它能够通用到所有的URL搜索

效果展示

  • 使用前
    image

  • 使用后
    image

脚本内容

// ==UserScript==
// @name         Search URL Cleaner (通用搜索引擎URL清理)
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  结合精确匹配与动态扩展,自动清理搜索引擎URL中的多余参数。
// @author       You & AI Assistant
// @match        https://www.google.com/search*
// @match        https://www.google.co.jp/search*
// @match        https://www.google.com.hk/search*
// @match        https://www.google.*.*/search*  // 通配符匹配其他Google国际域名
// @match        https://www.bing.com/search*
// @match        https://www.baidu.com/s*
// @match        https://www.baidu.com/search*
// @match        https://duckduckgo.com/*
// @match        https://*.yahoo.com/search*
// @match        https://*.startpage.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    /**
     * 配置对象
     * key: 搜索引擎的主机名或通用模式
     * value: 一个数组,包含应保留的 URL 参数。
     */
    let allowedParamsConfig = {
        // Google 的主配置,将被动态应用到其他Google域名
        'www.google.com': ['q', 'tbm', 'start', 'hl', 'lr'],
        'www.bing.com':   ['q', 'first', 'count', 'FORM'],
        'www.baidu.com':  ['wd', 'word', 'pn', 'rn'],
        'duckduckgo.com': ['q', 'ia', 'iax'],
        'yahoo.com':      ['p', 'q', 'ei', 'fr'],
        'startpage.com':  ['query', 'cat', 'sc']
    };

    // --- 动态配置 Google 国际域名 ---
    // 如果当前是 Google 国际域名,则动态添加到配置中
    const hostname = window.location.hostname;
    if (hostname.startsWith('www.google.') && hostname !== 'www.google.com' && !allowedParamsConfig.hasOwnProperty(hostname)) {
        // 从 www.google.com 获取配置并复制
        allowedParamsConfig[hostname] = [...allowedParamsConfig['www.google.com']];
    }
    // --- 动态配置结束 ---

    /**
     * 主函数:清理当前页面的 URL
     */
    function cleanUrl() {
        const currentHostname = window.location.hostname;
        let allowedKeys = allowedParamsConfig[currentHostname];

        // 如果当前主机名不在配置中,尝试更通用的匹配
        if (!allowedKeys) {
             // 可以根据需要扩展更多通用匹配逻辑
             // 例如,对于所有 google.* 域名,如果上面的动态配置没有生效
             if (currentHostname.startsWith('www.google.')) {
                 allowedKeys = allowedParamsConfig['www.google.com']; // 使用通用Google配置
             }
             // 对于Yahoo等子域名
             else if (currentHostname.endsWith('.yahoo.com')) {
                 allowedKeys = allowedParamsConfig['yahoo.com'];
             }
             // 对于Startpage等子域名
             else if (currentHostname.endsWith('.startpage.com')) {
                 allowedKeys = allowedParamsConfig['startpage.com'];
             }
        }

        // 如果仍然没有找到匹配的配置,则退出
        if (!allowedKeys) {
            return;
        }

        const originalUrl = new URL(window.location.href);
        const originalParams = originalUrl.searchParams;

        // 创建一个新的、干净的参数对象
        const cleanParams = new URLSearchParams();

        // 遍历允许的参数列表,从原始 URL 中提取它们并添加到新参数对象中
        for (const key of allowedKeys) {
            if (originalParams.has(key)) {
                // 使用 getAll 来处理可能重复的参数
                originalParams.getAll(key).forEach(value => {
                    cleanParams.append(key, value);
                });
            }
        }

        // --- 路径特殊处理 ---
        let pathname = originalUrl.pathname;
        if (currentHostname === 'duckduckgo.com') {
            pathname = '/'; // DuckDuckGo 的搜索结果路径是根路径
        }
        // --- 路径处理结束 ---

        const newUrl = originalUrl.origin + pathname + '?' + cleanParams.toString();

        // 仅当 URL 确实需要清理时,才更新地址栏
        if (window.location.href !== newUrl) {
            try {
                window.history.replaceState(null, null, newUrl);
                console.log('URL Cleaner (融合版): URL has been simplified to:', newUrl);
            } catch (e) {
                // 在某些情况下 replaceState 可能失败(例如在某些框架内)
                console.warn('URL Cleaner: Failed to update URL with replaceState', e);
            }
        }
    }

    // 立即执行清理(在文档开始加载时)
    if (document.readyState === 'loading') {
        window.addEventListener('DOMContentLoaded', cleanUrl);
    } else {
        // 如果脚本在页面加载后注入,则直接执行
        cleanUrl();
    }

    // 使用 Navigation API 或 PopStateEvent 监听浏览器导航和URL变化
    // 这对于现代单页应用(SPA)的搜索切换非常有效
    // 优先使用更现代的 Navigation API (如果支持)
    if ('navigation' in window) {
        window.navigation.addEventListener('navigate', (event) => {
            // 简单判断是否是搜索相关的导航,可以更精细
             if (event.destination?.url && Object.keys(allowedParamsConfig).some(domain => event.destination.url.includes(domain))) {
                 // 导航后延迟执行,确保新URL已生效
                 setTimeout(cleanUrl, 100);
             }
        });
    } else {
        // 降级方案:使用 PopStateEvent 监听浏览器前进后退
        window.addEventListener('popstate', cleanUrl);
    }

    // 作为后备,使用一个 MutationObserver 来监听DOM变化
    // 这对于一些不触发 popstate 的动态内容加载可能有效
    const observer = new MutationObserver(() => {
        // 防抖,避免频繁调用
        clearTimeout(observer.timeoutId);
        observer.timeoutId = setTimeout(cleanUrl, 200);
    });

    observer.observe(document, { childList: true, subtree: true });

})();

posted @ 2025-09-27 09:05  一心一弈  阅读(19)  评论(0)    收藏  举报