油猴js 获取替换网页链接并重定向
'# 油猴js 获取替换网页链接并重定向
一、背景与问题
在Web开发中,有时需要对第三方网站的链接进行动态处理。例如:
- 将所有外部链接统一跳转到自建的网关
- 替换特定网站的图片链接为CDN版本
- 过滤广告链接
- 实现个性化链接策略
传统方式需要修改源站代码或部署中间服务器,但这些方案存在显著局限性:
- 修改源站代码成本高,且无法对第三方站点生效
- 中间服务器方案需要处理大量并发请求,运维成本高
- 需要用户配合部署,难以快速生效
油猴(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.querySelectorAll或MutationObserver获取链接元素:
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.location或window.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、正则表达式和性能优化技巧,可以实现高效的链接处理方案。同时要注意安全风险,避免滥用脚本功能。对于复杂需求,建议结合服务器端处理,形成完整的解决方案。
评论已关闭