通用网页广告监测,ADBlock plus算法的C#实现。

最近接到一个需求:随便给一个网页,要求检测出里面的广告。

看到这需求,第一时间想到了firefox中的adblock plus,adblock plus是基于规则包来过滤广告,里面的广告描述规则也许能拿来用。于是折腾了一晚上,实现了一个简单的东西来满足需求,效果还不错

adblock plus工作原理:

adblock plus是先把过滤规则全部转换成正则表达式。再用这些正则表达式去过滤广告。

我思路如下:

1.实现一个adblock plus规则解析器,把adblock plus的广告过滤规则 转换成正则表达式。

2.得到一个要检测广告的页面后,解析出这个页面的所有链接。遍历所有链接,应用第一步得到的正则表达式规则判断链接是否广告。

第一步基于对正则表达式的理解简单的实现了下,如"."转换成"\\.","*"转换成".*"等,元素隐藏规则暂时不处理。adblock plus规则说明:http://code.google.com/p/adblock-chinalist/wiki/Writing_Adblock_Plus_filters

第二步,(adblock plus详细的匹配算法:http://adblockplus.org/blog/investigating-filter-matching-algorithms)经过第一步处理后,得到了几千条广告过滤正则表达式。 怎么解析出一个页面的所有链接就不说了,到这里时,收到有一大堆有待判断的链接,和一大堆用于判断的正则表达式规则,普通的思路是对于每一条链接,遍历所有规则判断是否匹配,代码如下:

function getMatchingFilter1(S, F)
  
for each filter in F
    
if (filter matches S)
      
return filter
    end 
if
  end 
for
  
return null
end 
function
 

但这样效率惨不忍睹。还好adblock plus中给出了一个不错的解决方案,对每一条过滤规则抽取出一个代表这条过滤规则的唯一key值,把这些放在哈希表中。于是对一条链接的判断不用遍历所有的规则,而是先在哈希表中查找出有可能匹配的规则再匹配。

对于查找出有可能 匹配的规则,adblock中用来一个奇妙的算法:Boyer-Moore algorithm

adblock plus中实现如下:

function initializeHashTable3(H, J, C, m)
  
for each c in C
    H(c) :
= filter(c)
    
for i in (0 .. m/2)
      substring := c.substring(i, m/2)
      jump := m/2 - i
      if substring not in J or J(substring) > jump
        J(substring) :
= jump
      end 
if
    end 
for
  end 
for
end 
function

function getMatchingFilter3(S, H, J, m)
  endPtr :
= m
  
while endPtr <= n
    substring :
= S.substring(endPtr - m/2, m/2)
    
if substring in J and J[substring] > 0
      endPtr :
= endPtr + J[substring]
    
else if substring in J and J[substring] = 0
      substring :
= S.substring(endPtr - m, m)
      
if (substring in H and H(substring) matches S)
        
return H(substring)
      
else
        endPtr :
= endPtr + 1
      end 
if
    
else
      endPtr :
= endPtr + m/2 + 1
    end if
  end 
while

  
return null
end 
function

其中参数说明:

H是存放每一天规则生成的唯一key的哈希表,value是这条规则。
J存放的是跳过多少位字符的信息,Boyer-Moore算法要用到的。
C是是存放每一天规则生成的唯一key的集合。
M是每一条规则生成的key的长度,是8,没为什么。
S是要判断的链接。

我的实现就是,蹬蹬蹬蹬,就是翻译成C#版本:
public void InitializeHashTable(Dictionary<stringstring> H, Dictionary<stringint> J, List<string[]> C)
{
    foreach (string[] kv in C)
    {
        string key = kv[0];
        string ruleText = kv[1];
        if (!H.ContainsKey(key))
        {
            H.Add(key, ruleText);
        }

       
for (int i = 0; i <= 4; i++)
        {
           
int jump = 4 - i;
           
string childKey = key.Substring(i, 4);
           
if (!J.ContainsKey(childKey) || J[childKey] > jump)
            {
                J[childKey] 
= jump;
            }
        }
    }
}

private string GetMatchingFilter(string url,Dictionary<stringstring> H, Dictionary<stringint> J)
{
    int endPtr = 8;
   
while (endPtr <= url.Length)
    {
       
string key = url.Substring(endPtr - 44);

       
if (J.ContainsKey(key) && J[key] > 0)
        {
            endPtr 
+= J[key];
        }
       
else if (J.ContainsKey(key) && J[key] == 0)
        {
            key 
= url.Substring(endPtr - 88);

           
if (H.ContainsKey(key) && Regex.IsMatch(url, H[key], options))
            {
               
return H[key];
            }
           
else
            {
                endPtr
++;
            }
        }
       
else
        {
            endPtr 
= endPtr + 5;
        }
    }

   
return null;
}
完成,求交流。文中所用到的资料:
 
原文地址:https://www.cnblogs.com/pwg17/p/1966318.html