在前文《Angular 项目如何接入 Google Adsense,并实现动态读取配置和反 Adblock Plus 拦截?》中,提到了如何进行 Adblock Plus、AdGuard 等广告拦截插件的检测,本文对此作一详细分析。
目前网络上常见的检测方式有几种:
- 设置全局变量,并将其文件名命名为类似
ads.js
等带关键词的名字。 - 设置定时器,在定时器中检测某个元素是否能正常显示。
一个典型的实现,如阮一峰的 Blog:
typescriptCopy code- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
function checker() {
if (/mobile|android/i.test(navigator.userAgent)) return;
var img = document.querySelector('a > img[src*="wangbase.com/blogimg/asset/"]');
var isAdblocker = (typeof adblock === 'undefined');
if (
(img && window.getComputedStyle(img).display === 'none') ||
(img && window.getComputedStyle(img.parentElement).display === 'none')
){
var sponsor = document.querySelector('#main-content');
var prompt = document.createElement('div');
prompt.style = 'border: 1px solid #c6c6c6;border-radius: 4px;background-color: #f5f2f0;padding: 15px; font-size: 14px;';
prompt.innerHTML = '<p>您使用了广告拦截器,导致本站内容无法显示。</p><p>请将 www.ruanyifeng.com 加入白名单,解除广告屏蔽后,刷新页面。谢谢。</p>';
sponsor.parentNode.replaceChild(prompt, sponsor);
}
}
setTimeout(checker, 1000);
function checker() {
if (/mobile|android/i.test(navigator.userAgent)) return;
var img = document.querySelector('a > img[src*="wangbase.com/blogimg/asset/"]');
var isAdblocker = (typeof adblock === 'undefined');
if (
(img && window.getComputedStyle(img).display === 'none') ||
(img && window.getComputedStyle(img.parentElement).display === 'none')
){
var sponsor = document.querySelector('#main-content');
var prompt = document.createElement('div');
prompt.style = 'border: 1px solid #c6c6c6;border-radius: 4px;background-color: #f5f2f0;padding: 15px; font-size: 14px;';
prompt.innerHTML = '您使用了广告拦截器,导致本站内容无法显示。
请将 www.ruanyifeng.com 加入白名单,解除广告屏蔽后,刷新页面。谢谢。
';
sponsor.parentNode.replaceChild(prompt, sponsor);
}
}
setTimeout(checker, 1000);
这两种方式的原理其实也很简单:
- 利用广告拦截插件的关键词检测特性。
- 利用是否拦截的实际结果,如上例中,自定义了需拦截的 URL,从而在检测到未显示元素(图片)时,判断开启了广告拦截插件。
然而,这两种方式要么无效,要么过于复杂,并不想采用。实际上,通过 Google AdSense、百度联盟的广告调用代码可以很容易地找到解决方案。
Google AdSense 的调用代码:
typescriptCopy code- 1
(adsbygoogle = window.adsbygoogle || []).push({});
(adsbygoogle = window.adsbygoogle || []).push({});
百度联盟的调用代码:
typescriptCopy code- 1
- 2
- 3
- 4
- 5
(window.slotbydup = window.slotbydup || []).push({
id: "u6001133",
container: "_iweq3ve2cyf",
async: true
});
(window.slotbydup = window.slotbydup || []).push({
id: "u6001133",
container: "_iweq3ve2cyf",
async: true
});
有没有发现一些端倪?
可以看到,二者都将广告对象模拟成了数组(实际上是对象),并在 js 被拦截之后成为了真正的数组。这么做的原因也很简单,防止报错。但,我们也可以很容易地利用这一特点来检测是否开启了广告拦截插件。
typescriptCopy code- 1
- 2
- 3
- 4
- 5
- 6
if (Array.isArray((window as any).adsbygoogle)) {
this.console.warn('Ads is blocked.');
this.hideAdsEle();
} else {
this.commonService.updateAdsFlag(false);
}
if (Array.isArray((window as any).adsbygoogle)) {
this.console.warn('Ads is blocked.');
this.hideAdsEle();
} else {
this.commonService.updateAdsFlag(false);
}
上述代码中,只需要一行 Array.isArray
调用即可完成广告是否被拦截的判断。
实际上,这种方式适用于检测任何类型的广告拦截插件,包括因网络等各种问题导致的 js 加载失败。
完美![]~( ̄▽ ̄)~*
实际效果可以直接在本页面上体验(切换广告拦截插件启用状态)。
完整代码请访问:https://github.com/ifuyun/ifuyun.com。