AdBlock广告拦截插件的实现原理
在這里,我不會(huì)解釋太多的代碼,沒有必要,說說原理就可以了。
AdBlock的廣告攔截實(shí)際上分為2個(gè)部分:
1、對(duì)于URL請(qǐng)求的攔截
這一般都是頁面中DIV元素嵌入一個(gè)IFRMAE/IMAGE元素,然后加載一個(gè)廣告鏈接或者GIF圖片什么的。
這部分的規(guī)則庫描述比較復(fù)雜。規(guī)則大概有幾萬條,即使對(duì)于國(guó)內(nèi)的使用,可能也會(huì)有個(gè)1000條左右。
不過我覺得沒必要搞這么復(fù)雜,可以通過提取出最常見的100條,然后用這100條屏蔽80%的請(qǐng)求,就可以了。
這些規(guī)則的語法,基本上是對(duì)于URL中domain和path的字符串前綴或后綴匹配??赡芨綆б恍╊~外的屬性(理論上說來,這些屬性都應(yīng)該可以從NetworkRequest對(duì)象中獲取到)
AdBlock Plus的作者實(shí)際上是使用JavaScript把這些URL匹配規(guī)則映射為了正則表達(dá)式,然后再用正則表達(dá)式對(duì)目標(biāo)URL進(jìn)行匹配過濾。
當(dāng)然,也可以用Java來實(shí)現(xiàn)。前面已經(jīng)說了,正則表達(dá)式是基于前綴或者后綴的,前綴可以用Trie樹,后綴可以反轉(zhuǎn)后當(dāng)作前綴處理。
而對(duì)于keyword in查詢,可以使用基于編譯自動(dòng)機(jī)的AC算法(我認(rèn)為AC算法其實(shí)就是一個(gè)簡(jiǎn)化版的 key1|key2|key3|...|keyn 這種形式的正則表達(dá)式而已)
一旦匹配上,在shouldOverrideUrlLoading函數(shù)里return true;代表已額外處理,實(shí)際上不處理,這樣就屏蔽了此URL請(qǐng)求。(shouldOverrideUrlLoading主要是用于特殊的scheme協(xié)議的,用于URL請(qǐng)求攔截實(shí)屬誤用),好像有額外的shouldIgnoreNetworkRequest
2、對(duì)于頁面DOM嵌入廣告內(nèi)容的處理
基于規(guī)則是,通過CSS3 Selector定位到這些DOM元素,然后設(shè)置其display等于none !important。
AdBlock Plus對(duì)于頁面內(nèi)容的廣告過濾是特定于網(wǎng)站的,也就是說,是對(duì)于domain字符串的精確匹配。這里使用一個(gè)簡(jiǎn)單的HashMap性能也就足夠可以了。
問題是,有些廣告內(nèi)容是延遲加載的(通過setTimer),對(duì)于這部分內(nèi)容,只能等個(gè)幾秒鐘等廣告內(nèi)容出來之后,才注入執(zhí)行JS腳本。
當(dāng)然,這種方法不是很好,最好是在瀏覽器內(nèi)核里做一個(gè)DOM Mutation事件監(jiān)控的daemon:如果檢測(cè)到有新的DOM節(jié)點(diǎn)加入,當(dāng)然必須是在DOM Content Loaded之后,就發(fā)送一個(gè)通知給客戶端,客戶端再調(diào)度廣告屏蔽腳本的重新執(zhí)行。
上面2類處理看起來有效,實(shí)際上無效。設(shè)想網(wǎng)站要求用戶必須訪問廣告服務(wù)器,以提高一個(gè)特殊的cookie,這樣才允許用戶訪問資源。這樣第1種方法其實(shí)就沒用武之地了。對(duì)于第2種則更簡(jiǎn)單,原則上來說,如果把廣告跟正常內(nèi)容混合在一起,你是沒辦法用計(jì)算機(jī)算法來區(qū)分誰是廣告誰是正常內(nèi)容的,除非用人來維護(hù)。或者立法。
從個(gè)人角度考慮,某部分廣告則讓讓它下載顯示也無不可,如果用戶覺得它煩,就提供一個(gè)規(guī)則添加的UI交互入口。而對(duì)于彈窗、閃爍的GIF這類比較惡心的,殺之可也。
1/15更新:
AdBlock?Plus做到的優(yōu)化:假如一個(gè)URL為a.b.c,那么這個(gè)URL只會(huì)跟過濾規(guī)則里包含a,或者b,或者c的規(guī)則做匹配,后者還是得一個(gè)一個(gè)的執(zhí)行JS正則表達(dá)式線性匹配好處就是那些規(guī)則中不包含a,b,c的將不會(huì)與這個(gè)url做匹配。這可能使得把一個(gè)10000條規(guī)則的總線性掃描降低到了1000條的規(guī)模。
但是,它還是沒有獵豹瀏覽器的做法好:AdBlock?Plus最終URL與過濾規(guī)則的匹配還是用JS正則表達(dá)式來執(zhí)行的(當(dāng)然,JS里的字符串高級(jí)處理都只能用用正則表達(dá)式,逐個(gè)字符比較對(duì)JS代碼來說不現(xiàn)實(shí)),獵豹對(duì)于簡(jiǎn)單的前綴/后綴匹配可以使用Trie樹或AC自動(dòng)機(jī),但這是基于字符的,只能在Java里執(zhí)行才有效率。
不過,我想,更有技術(shù)含量的,是引入?yún)f(xié)作式過濾:當(dāng)用戶標(biāo)明網(wǎng)頁中的某個(gè)元素屬于廣告,那么,瀏覽器內(nèi)核可以智能地定位到這個(gè)DOM元素,并生成一個(gè)有效的CSS Selector(這個(gè)就是難度之所在了),這樣就可以動(dòng)態(tài)地?cái)U(kuò)展用戶的本地過濾規(guī)則庫,然后再通過上傳到云端服務(wù)器形成大數(shù)據(jù),從中挖掘出公共的廣告攔截規(guī)則庫。
總結(jié)
以上是生活随笔為你收集整理的AdBlock广告拦截插件的实现原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 驻定相位原理(POSP)的简单应用
- 下一篇: 【软件开发底层知识修炼】十七 快速学习G