目录导读

- 为什么需要“脚本级”广告屏蔽? —— 插件失效的痛点与底层逻辑
- 核心原理解剖 —— 浏览器扩展(如Tampermonkey)如何“劫持”网页
- 实战三大脚本策略 —— 从“删元素”到“拦请求”的进阶之路
- 经典代码拆解 —— 手写一个“极简去广告”油猴脚本
- 高难度场景应对 —— 动态加载、懒加载与反屏蔽检测的博弈
- 常见问题问答(FAQ) —— 解决你90%的脚本运行报错
为什么需要“脚本级”广告屏蔽?
很多用户依赖AdBlock等现成插件,但经常发现:某些网站检测到广告拦截器后,强制要求“关闭拦截”或直接黑屏,更深层的痛点是——规则列表(如EasyList)更新滞后,新式广告(如原生信息流、伪装成正文的推广)防不胜防。
脚本(UserScript)的核心优势在于“定制化”和“即时性”,它由用户自己编写或从社区获取,直接运行在网页的Document Object Model(DOM)层面,你可以精准地告诉浏览器:“这个class为ad-banner的div,加载完就立刻给我撕掉”,这种“外科手术式”的屏蔽,远比依赖过滤列表的插件更灵活,且不易被网站navigator属性检测(因为脚本不干预网络请求,只操作页面渲染)。
核心原理解剖:浏览器扩展如何“劫持”网页
要运行脚本,你需要一个“容器”——最主流的是Tampermonkey(篡改猴) 或Violentmonkey,它的工作原理分三步:
- 注入:当浏览器加载网页时,扩展根据你设定的
@match规则(如*://*.example.com/*),将你的JavaScript代码注入到页面顶层上下文(document已就绪)。 - 监听:脚本会挂载
MutationObserver(观察DOM变化),无论广告是静态写在HTML里,还是后期用AJAX动态插入,只要DOM树有“新节点”加入,观察器就会触发回调。 - 执行:在回调里,你编写逻辑(如
element.remove())将广告节点从DOM中剥离,由于操作发生在渲染引擎绘制前或绘制间隙,用户通常看不到任何闪烁。
实战三大脚本策略:进阶之路
根据广告的“顽固程度”,脚本策略分为三个层级:
- 策略A:CSS隐藏(最快速) ,对
style标签动态注入CSS,例如document.styleSheets[0].insertRule('.ad {display:none !important;}'),优点是不消耗CPU,缺点是广告请求已发出,浪费流量。 - 策略B:DOM移除(最干净) ,这是主流做法,直接删节点,关键代码:
const kill = (e) => e.remove()。 - 策略C:请求拦截(最底层) ,在脚本里重写
window.fetch或XMLHttpRequest原型,判断URL包含/ad/、g.doubleclick.net等关键词时直接返回空数据,这能彻底阻止广告数据下载,省流且提快速度,但要注意,此类脚本极易被网站的反作弊机制追踪,需谨慎使用。
经典代码拆解:手写“极简去广告”脚本
直接上干货,打开Tampermonkey,新建脚本,粘贴以下代码:
// ==UserScript==
// @name 极简去广告·通用版
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 清除常见广告类名与固定尺寸占位
// @author YourName
// @match *://*/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
// 定义要清除的广告特征(类名、ID、特征属性)
const AD_SELECTORS = [
'.ad', '.ads', '.advert', '#banner_ad',
'[class*="ad-list"]', '[id*="google_ads"]',
'iframe[src*="doubleclick"]', 'iframe[src*="adsbygoogle"]'
];
// 核心清除函数
function removeAds() {
AD_SELECTORS.forEach(selector => {
document.querySelectorAll(selector).forEach(el => {
el.remove(); // 直接移除节点
});
});
}
// 策略1:页面初始加载完成时
window.addEventListener('load', removeAds);
// 策略2:针对动态加载的广告(MutationObserver监控)
const observer = new MutationObserver((mutations) => {
// 防抖处理,避免频繁触发
if (window.__adTimer) clearTimeout(window.__adTimer);
window.__adTimer = setTimeout(removeAds, 100);
});
observer.observe(document.documentElement, { childList: true, subtree: true });
})();
代码解释:@run-at document-start保证尽早注入。MutationObserver监听childList(子节点变动)。setTimeout防抖——避免快速删除一个节点导致又触发一次观察,造成死循环。
高难度场景应对:动态加载与反屏蔽
- 动态广告(懒加载) :很多网站用
IntersectionObserver,当广告滚动到视口时才插入图片,你的脚本需要判断:如果广告节点存在但不含src,可以先替换成data-src然后删除。 - 反屏蔽检测:网站会检查
document.querySelectorAll('div').length是否异常少,从而判定你有脚本,应对方式是不要删广告,而是“撑破”它,例如将广告iframe的height设为1px,opacity设为0,且不触发remove(),让网站误以为广告还在正常显示。
常见问题问答(FAQ)
-
问:为什么我的脚本在百度贴吧不生效? 答:看控制台报错,大概率是广告容器不在
@match *://*/*范围内?或者贴吧使用了Shadow DOM(影子节点),普通querySelector无法穿透,解决方案:使用element.shadowRoot.querySelector()递归查找。 -
问:脚本能屏蔽视频网站的60秒广告吗? 答:可以,但机制不同,视频广告通常是
<video>标签的事件流,你需要拦截播放器的ads事件,或者重写播放器的playAd方法,这属于高级破解范畴,极易被封号,不推荐普通用户尝试。 -
问:如何过滤掉“伪装成文章”的原生广告? 答:这类广告没有特征
class,通常用rel="nofollow"属性或sponsored标注,脚本可以遍历所有<a>标签,检查rel属性,如果含sponsored,就把整个父级<article>隐藏。 -
问:脚本不小心屏蔽了正常内容,如何恢复? 答:在Tampermonkey面板里关闭该脚本,刷新页面,若恢复,则说明选择器匹配错误,建议在浏览器控制台用
document.querySelectorAll测试你的选择器,确认唯一性后再写入脚本。 -
问:手机浏览器支持油猴脚本吗? 答:支持,安卓用Kiwi Browser(桌面级扩展支持),iOS用Userscripts(Safari扩展),但注意手机端脚本要避免重CPU的DOM操作,以免耗电。
脚本屏蔽广告的本质是一场前端权限争夺战,你通过代码拿回了浏览器的“渲染控制权”,本文提供的策略足以应对95%的常规广告形态,但请记住:你可以利用这些技术保护浏览体验,但请勿将脚本用于非法抓取或恶意篡改他人站点内容,下次看到恼人的弹窗时,不必怒摔鼠标——打开你的脚本编辑器,用一行document.querySelector('#close-ads').click()去征服它吧。 (全文完)