油猴js 获取替换网页链接并重定向

'# 油猴js 获取替换网页链接并重定向

一、背景与问题

在Web开发中,有时需要对第三方网站的链接进行动态处理。例如:

  • 将所有外部链接统一跳转到自建的网关
  • 替换特定网站的图片链接为CDN版本
  • 过滤广告链接
  • 实现个性化链接策略

传统方式需要修改源站代码或部署中间服务器,但这些方案存在显著局限性:

  1. 修改源站代码成本高,且无法对第三方站点生效
  2. 中间服务器方案需要处理大量并发请求,运维成本高
  3. 需要用户配合部署,难以快速生效

油猴(Tampermonkey)脚本作为浏览器扩展,提供了独特解决方案。它能够通过JavaScript直接操作DOM,实现对网页链接的动态处理。本文将深入探讨其技术原理、实现方法和实际应用场景。

二、基本原理

1. 油猴脚本的执行机制

油猴脚本通过以下流程注入网页:

// 油猴脚本模板
// @name         My Link Rewriter
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  替换网页所有链接
// @match        https://example.com/*
// @grant        GM_addElement
(function() {
    'use strict';
    // 脚本逻辑
})();
  • @match定义匹配的URL规则
  • @grant声明使用的API权限
  • 脚本在页面加载完成后注入

2. DOM操作原理

通过document.querySelectorAllMutationObserver获取链接元素:

document.querySelectorAll('a').forEach(link => {
    const originalUrl = link.href;
    const newUrl = replaceUrl(originalUrl);
    if (newUrl !== originalUrl) {
        link.href = newUrl;
    }
});
  • querySelectorAll会捕获所有静态链接
  • 动态生成的链接需要通过MutationObserver监听DOM变化

3. 重定向机制

通过修改href属性实现重定向,或通过window.location强制跳转:

// 重定向方式1
window.location.href = 'https://new-url.com';

// 重定向方式2
document.location = 'https://new-url.com';

三、环境准备

1. 安装油猴插件

在Chrome/Firefox中安装Tampermonkey扩展,支持以下浏览器:

  • Chrome 88+
  • Firefox 85+
  • Edge 88+
  • Brave 1.38+

2. 创建脚本文件

创建link-rewriter.js文件,内容如下:

// ==UserScript==
// @name         Link Rewriter
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Replace links on the page
// @match        https://example.com/*
// @grant        GM_addElement
// ==/UserScript==
(function() {
    'use strict';
})();

四、核心实现

1. 链接替换逻辑

function replaceUrl(url) {
    // 示例:将所有https://example.com/替换为https://new.example.com/
    return url.replace(/^https:\/\/example\.com\//, 'https://new.example.com/');
}
  • 使用正则表达式进行URL匹配
  • 可支持多级替换规则
  • 可添加白名单/黑名单机制

2. 动态链接处理

使用MutationObserver监听DOM变化:

const observer = new MutationObserver(mutations => {
    mutations.forEach(mutation => {
        if (mutation.type === 'childList') {
            const links = Array.from(mutation.addedNodes)
                .filter(node => node.nodeName === 'A')
                .map(node => node.href);
            links.forEach(href => {
                const newUrl = replaceUrl(href);
                if (newUrl !== href) {
                    const link = document.querySelector(`a[href="${href}"]`);
                    if (link) {
                        link.href = newUrl;
                    }
                }
            });
        }
    });
});

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

3. 链接重定向逻辑

function redirectUrl(url) {
    // 示例:将所有外部链接跳转到指定网关
    if (url.startsWith('http://') || url.startsWith('https://')) {
        const gatewayUrl = 'https://gateway.example.com/redirect?url=' + encodeURIComponent(url);
        window.location.href = gatewayUrl;
    }
}

五、完整案例

1. 案例:替换特定网站的图片链接

// ==UserScript==
// @name         Image Link Replacer
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Replace image links on a specific site
// @match        https://example.com/*
// @grant        GM_addElement
// ==/UserScript==
(function() {
    'use strict';

    // 替换规则:将所有https://example.com/images/替换为https://cdn.example.com/
    function replaceImageLinks() {
        const imageLinks = document.querySelectorAll('img[src]');
        imageLinks.forEach(link => {
            const originalSrc = link.src;
            const newSrc = originalSrc.replace(
                /^https:\/\/example\.com\/images\//, 
                'https://cdn.example.com/'
            );
            if (newSrc !== originalSrc) {
                link.src = newSrc;
            }
        });
    }

    // 监听DOM变化
    const observer = new MutationObserver(replaceImageLinks);
    observer.observe(document.body, { childList: true, subtree: true });

    // 初始加载时执行
    replaceImageLinks();
})();

2. 案例:过滤广告链接

// ==UserScript==
// @name         Ad Link Filter
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Remove suspicious links
// @match        https://example.com/*
// @grant        GM_addElement
// ==/UserScript==
(function() {
    'use strict';

    // 过滤规则:移除包含"ad"或"ads"的链接
    function filterLinks() {
        const links = document.querySelectorAll('a');
        links.forEach(link => {
            const href = link.href;
            if (href && (href.includes('ad') || href.includes('ads'))) {
                link.style.display = 'none';
                link.remove();
            }
        });
    }

    // 监听DOM变化
    const observer = new MutationObserver(filterLinks);
    observer.observe(document.body, { childList: true, subtree: true });

    // 初始加载时执行
    filterLinks();
})();

六、源码解析

1. MutationObserver详解

const observer = new MutationObserver(mutations => {
    mutations.forEach(mutation => {
        if (mutation.type === 'childList') {
            // 处理新增节点
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === 1 && node.nodeName === 'A') {
                    const link = node;
                    const originalUrl = link.href;
                    const newUrl = replaceUrl(originalUrl);
                    if (newUrl !== originalUrl) {
                        link.href = newUrl;
                    }
                }
            });
        }
    });
});
  • nodeType === 1表示元素节点
  • node.nodeName === 'A'筛选锚点标签
  • href属性包含完整的URL

2. 正则表达式优化

const pattern = /^https:\/\/example\.com\/(.*?)(\.(?:jpg|png|gif|mp4|pdf))$/;
const match = url.match(pattern);
if (match) {
    const newUrl = `https://cdn.example.com/${match[1]}${match[2]}`;
    link.href = newUrl;
}
  • 使用捕获组提取文件名
  • 支持多种文件类型
  • 可避免误匹配非链接内容

七、进阶使用

1. 动态配置管理

// 从localStorage读取配置
const config = JSON.parse(localStorage.getItem('linkRewriterConfig') || '{}');

function replaceUrl(url) {
    const rules = config.rules || [];
    for (const rule of rules) {
        const { pattern, replacement } = rule;
        if (url.match(pattern)) {
            return url.replace(pattern, replacement);
        }
    }
    return url;
}

2. 多规则匹配策略

function matchRules(url, rules) {
    for (const rule of rules) {
        if (url.match(rule.pattern)) {
            return rule;
        }
    }
    return null;
}

3. 性能优化技巧

// 使用节流控制重计算频率
let isProcessing = false;
function throttle(func, delay) {
    return (...args) => {
        if (!isProcessing) {
            isProcessing = true;
            func.apply(null, args);
            setTimeout(() => isProcessing = false, delay);
        }
    };
}

const throttledProcess = throttle(processLinks, 200);

八、性能与工程实践

1. 性能优化方法

  • 使用requestIdleCallback进行非紧急处理
  • 避免频繁的DOM遍历
  • 使用IntersectionObserver进行懒加载处理
  • 对大型页面进行分块处理

2. 异常处理机制

try {
    const link = document.querySelector('a');
    if (link && link.href) {
        const newUrl = replaceUrl(link.href);
        link.href = newUrl;
    }
} catch (e) {
    console.error('Error processing link:', e);
}

3. 安全风险分析

  • 脚本可能被恶意使用:

    • 可能导致隐私泄露
    • 可能被用于网络钓鱼
    • 可能破坏网页完整性
  • 防御措施:

    • 对URL进行严格校验
    • 避免处理敏感信息
    • 使用GM_getValue保存敏感配置
    • 对用户输入进行过滤

九、常见问题与踩坑

1. 常见错误示例

// 错误示例:未处理动态加载内容
document.querySelectorAll('a').forEach(link => {
    link.href = replaceUrl(link.href);
});
  • 问题:无法处理动态加载的链接
  • 解决:使用MutationObserver监听DOM变化

2. 链接重定向问题

// 错误示例:直接跳转导致页面刷新
window.location.href = 'https://new-url.com';
  • 问题:页面会完全刷新
  • 解决:使用document.locationwindow.open
  • 注意:window.open可能被浏览器拦截

3. 正则表达式陷阱

// 错误示例:未考虑URL编码
const url = 'https://example.com/path%20with%20space';
const newUrl = url.replace(/%20/g, '-');
  • 问题:未处理URL编码
  • 解决:使用decodeURIComponent先解码再处理

十、最佳实践

1. 推荐的实现方案

  • 使用MutationObserver监听DOM变化
  • 对URL进行严格校验
  • 使用requestIdleCallback进行非紧急处理
  • 对敏感操作进行异常捕获
  • 使用localStorage保存配置

2. 推荐的代码结构

// 推荐结构
(function() {
    'use strict';

    // 配置管理
    const config = JSON.parse(localStorage.getItem('myConfig') || '{}');

    // 工具函数
    function replaceUrl(url) {
        // 实现细节
    }

    // 主逻辑
    function main() {
        // 处理逻辑
    }

    // 初始化
    main();
})();

3. 推荐的测试方法

  • 使用console.log进行调试
  • 使用console.table查看数据
  • 使用performance.now()进行性能分析
  • 使用localStorage模拟配置

十一、总结

油猴脚本提供了对网页链接的灵活控制能力,但需要谨慎使用。在实际开发中:

  • 适用场景:需要对第三方网站进行个性化处理,或需要快速实现网页功能增强
  • 不适用场景:涉及敏感数据处理、需要高安全性的系统,或需要长期稳定的解决方案

通过合理使用MutationObserver、正则表达式和性能优化技巧,可以实现高效的链接处理方案。同时要注意安全风险,避免滥用脚本功能。对于复杂需求,建议结合服务器端处理,形成完整的解决方案。

最后修改于:2026年09月14日 19:32

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日