adblockplus简单介绍
官方源码:https://github.com/adblockplus/adblockpluscore
官网:https://adblockplus.org/
adblockplus通过定义规则来拦截广告,规则是根据广告url的特征指定的。当请求一个url的时候,会使用定义的规则对url进行匹配,如果有拦截规则匹配成功,则阻止该url请求;但是如果还匹配到白名单的规则,则不应阻止该请求。
拦截规则
更具体可以详见 https://adblockplus.org/zh_CN/filters
1. 定义黑名单规则
-
通配符:*
http://example.com/ads/banner123.gif
上面的广告url可以用下面的规则拦截,并且banner后面的数字改变了,也可以拦截
-
匹配网址开头/结尾:|
swf|
: 只会拦截swf结尾的url|http://adv
: 只会拦截http://adv开始的url||adv
:前面两条||并且后面直接跟着网址,则会忽略http与https的差异,同时拦截http://adv
、https://adv
和http://www.adv
-
标记分隔符:^
分隔符^可以表示除了字母、数字或者 _ - . % 之外的任何字符,此外URL的结尾也可以作为一个分隔符。
http://example.com^
会拦截http://example.com/
和http://example.com:8000/
, 但不会阻挡http://example.com.ar/
,因为^不会表示com后面的.
-
指定过滤规则选项
指定某些选项来指定规则的行为。列举这些选项的时候将它们放在美元符号 ($) 后面并用逗号 (,) 分割,放在过滤规则的最后面,例如:*/ads/*$script,match-case
部分支持的选项:
- 类型选项,如 script、image等,表示规则只作用于这些类型的请求
- third-party: 作用于第三方站点的请求
- 域名限定:选项 domain=example.com 指过滤规则只适用于 “example.com” 下的页面 。
- match-case:是否区分大小写
- 反转类型选项:在上述类型前面加上~,表示过滤规则 不 应用该类型
-
正则表达式,由于性能原因,建议尽可能避免使用正则表达式
2. 定义白名单规则
-
任何规则前面加上@@,就表示匹配到这条规则的url都不应该拦截,白名单的优先级高于黑名单。
例如:规则
@@advice
,可以避免下面的网址被规则adv
拦截掉:
3. 注释
- 注释以感叹号 (!) 开始
匹配算法
广告过滤的规则有几万条,如果每个请求的url都匹配一次所有规则,耗时会太长,所以adblockplus会将规则分类,减少实际需要匹配的规则。
1、规则分类
规则分类应在初始化时执行,分类的依据是规则中,规则选项(以$开始的)之前的部分中匹配[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])
的子串,这个匹配是不区分大小写的。举一个例子,以下的规则
||tool.hina.net/regex$script,match-case
匹配[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])
的会有下面的子串:
- |tool
- .hina
- .net
也就是规则中以一个特殊字符开始,后面跟着三个及以上非特殊字符并且非结尾的所有子串。然后再从上述子串中选择一个最长的,去掉第一个字符后作为规则的keyword,并将规则记录在这个keyword对应的一个数组中。如果有相同长度的子串,则会选择对应数组大小最小的一个作为keyword。
特殊的,无匹配的子串与正则表达式的keyword都是空字符串:“”。
keyword与对应的数组会作为键值对存在一个map中,黑名单与白名单的规则会分别记录在两个map。
所有规则都分类完之后,就初始化完了。
2、匹配url
判断一个url是否广告的步骤:
- 从url中提取出候选词列表
- url提取的候选词比提取规则的keyword简单:匹配
[a-z0-9%]{3,}
的所有子串,也就是长度大于等于三的不包含特殊字符的子字符串。如url:http://tool.hina.net/regex , 则候选词列表是:["http","tool","hina","net","regex"]
- 此外每个url的候选词列表都会加上空字符串“”,也就是空字符串对应的规则都会匹配一次,所以正则表达式的规则会比较影响性能,实际的候选词列表:
["http","tool","hina","net","regex",""]
- url提取的候选词比提取规则的keyword简单:匹配
- 分别从黑名单和白名单中取出每个候选词对应的规则数组
- 从上述map中按照候选词一一获取对应的规则数组
- 将url与取出的规则一一匹配
- 非正则表达式的规则会在匹配前转成正则表达式,再用正则表达式对url进行查找,如果有匹配的子串,则认为匹配成功
- 会按指定的过滤规则选项进行匹配
匹配的接口
/**
* Tests whether the URL matches any of the known filters
* @param {string} location
* URL to be tested
* @param {number} typeMask,指定类型
* bitmask of content / request types to match
* @param {string} [docDomain],指定当前页面的域名
* domain name of the document that loads the URL
* @param {boolean} [thirdParty],是否第三方请求,即url的源是否与当前页面的域名一致
* should be true if the URL is a third-party request
* @param {string} [sitekey]
* public key provided by the document
* @param {boolean} [specificOnly]
* should be <code>true</code> if generic matches should be ignored
* @returns {?RegExpFilter},返回匹配到的规则,返回的规则可以知道是属于黑名单还是白名单
* matching filter or <code>null</code>
*/
matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly)
匹配的时候只需要调用上述接口,所以在url请求之前判断一下,就可决定是否需要拦截。