網絡爬蟲之網頁排重:語義指紋

引言:網絡爬蟲讓咱們高效地從網頁獲取到信息,但網頁的重複率很高,網頁須要按內容作文檔排重,而判斷文檔的內容重複有不少種方法,語義指紋是其中比較高效的方法。
本文選自《網絡爬蟲全解析——技術、原理與實踐》。算法

  現代社會,有效信息對人來講就像氧氣同樣不可或缺。互聯網讓有效信息的收集工做變得更容易。當你在網上衝浪時,網絡爬蟲也在網絡中穿梭,自動收集互聯網上有用的信息。
  自動收集和篩選信息的網絡爬蟲讓有效信息的流動性加強,讓咱們更加高效地獲取信息。隨着愈來愈多的信息顯現於網絡,網絡爬蟲也愈來愈有用。
  不一樣的網站間轉載內容的狀況很常見。即便在同一個網站,有時候不一樣的URL地址可能對應同一個頁面,或者存在一樣的內容以多種方式顯示出來,因此,網頁須要按內容作文檔排重。
  例如,一個企業商品搜索。搜商品名,有一家公司發的商品名字都同樣,結果這家公司發的商品都顯示在前面,可是要求一家企業只顯示一條類似的商品在前面,能夠把近似重複的文檔權重下降,只保留一個文檔不下降權重。
  判斷文檔的內容重複有不少種方法,語義指紋的方法比較高效。語義指紋是直接提取一個文檔的二進制數組表示的語義,經過比較相等來判斷網頁是否重複。語義指紋是一個很大的數組,所有存放在內存會致使內存溢出,普通的數據庫效率過低,因此採用內存數據庫Berkeley DB。能夠經過Berkeley DB判斷該語義指紋是否已經存在。另一種方法是經過布隆過濾器來判斷語義指紋是否重複。
  提取網頁語義指紋的方法是:從淨化後的網頁中,選取最有表明性的一組關鍵詞,並使用該關鍵詞組生成一個語義指紋。經過比較兩個網頁的語義指紋是否相同來判斷兩個網頁是否類似。
  網絡上一度出現過不少篇關於「羅玉鳳徵婚」的新聞報道,其中的兩篇新聞內容對好比下表。
  【圖1】數據庫

  對於這兩篇內容相同的新聞,有可能提取出一樣的關鍵詞:「羅玉鳳」「徵婚」「北大」「清華」「碩士」,這就表示這兩篇文檔的語義指紋也相同。
  爲了提升語義指紋的準確性,須要考慮到同義詞,例如,「北京華聯」和「華聯商廈」能夠當作相贊成義的詞。最簡單的判斷方法是作同義詞替換。把「開業之初,比這還要多的質疑的聲音環繞在北京華聯決策者的周圍」替換爲「開業之初,比這還要多的質疑的聲音環繞在華聯商廈決策者的周圍」。
  設計同義詞詞典的格式是:每行一個義項,前面是基本詞,後面是一個或多個被替換的同義詞,請看下面的例子。數組

華聯商廈 北京華聯 華聯超市微信

  這樣能夠把「北京華聯」或「華聯超市」替換成「華聯商廈」。對指定文本,要從前日後查找同義詞詞庫中每一個要替換的詞,而後實施替換。同義詞替換的實現代碼分爲兩步。首先是查找Trie樹結構的詞典過程。網絡

public void checkPrefix(String sentence,int offset,PrefixRet ret) {  if (sentence == null || root == null || "".equals(sentence)) {
    ret.value = Prefix.MisMatch;
    ret.data = null;
    ret.next = offset;
    return ;
  }
  ret.value = Prefix.MisMatch;//初始返回值設爲沒匹配上任何要替換的詞
  TSTNode currentNode = root;
  int charIndex = offset;
  while (true) {    if (currentNode == null) {
          return;
    }
    int charComp = sentence.charAt(charIndex) - currentNode.splitchar;    if (charComp == 0) {
      charIndex++;      if(currentNode.data != null){
        ret.data = currentNode.data;//候選最長匹配詞
        ret.value = Prefix.Match;
        ret.next = charIndex;
      }      if (charIndex == sentence.length()) {
        return; //已經匹配完
      }      currentNode = currentNode.eqKID;
    } else if (charComp < 0) {      currentNode = currentNode.loKID;
    } else {      currentNode = currentNode.hiKID;
    }
  }
}

  而後是同義詞替換過程。app

//輸入待替換的文本,返回替換後的文本public static String replace(String content) throws Exception{  int len = content.length();
  StringBuilder ret = new StringBuilder(len);
  SynonymDic.PrefixRet matchRet = new SynonymDic.PrefixRet(null,null);  

  for(int i=0;i<len;){    //檢查是否存在從當前位置開始的同義詞
    synonymDic.checkPrefix(content,i,matchRet);    if(matchRet.value == SynonymDic.Prefix.Match) //若是匹配上,則替換同義詞
    {
      ret.append(matchRet.data);//把替換詞輸出到結果
      i=matchRet.next;//下一個匹配位置
    }    else //若是沒有匹配上,則從下一個字符開始匹配
    {
      ret.append(content.charAt(i));
      ++i;
    }
  }   return ret.toString();
}

  語義指紋生成算法以下所示。ide

  • 第1步:將每一個網頁分詞表示成基於詞的特徵項,使用TF*IDF做爲每一個特徵項的權值。地名、專有名詞等,名詞性的詞彙每每有更高的語義權重。網站

  • 第2步:將特徵項按照詞權值排序。ui

  • 第3步:選取前n個特徵項,而後從新按照字符排序。若是不排序,關鍵詞就找不到對應關係。spa

  • 第4步:調用MD5算法,將每一個特徵項串轉化爲一個128位的串,做爲該網頁的指紋。

調用fseg.result.FingerPrint中的方法。

String fingerPrint = getFingerPrint("","昨日,省城淵明北路一名17歲的少年在6樓晾毛巾時失足墜樓,摔在樓下的一輛麪包車上。麪包車受衝擊變形時吸取了巨大的副作用力能量,從而「救」了少年一命。目前,傷者尚無生命危險。據一位目睹者介紹,事故發生在下午2時40分許,當時這名在某美髮店工做的少年正站在陽臺上晾毛巾,因雨天陽臺溼滑而不當心摔下。 記者來到搶救傷者的醫院瞭解到,這名少年名叫李嘉誠,今年17歲,系豐城市人。李嘉誠受傷後,他表姐已趕到醫院陪護。據醫生介紹,傷者主要傷在頭部,具體傷情還有待進一步檢查。");String md5Value = showBytes(getMD5(fingerPrint));
System.out.println("FingerPrint:"+fingerPrint+" md5:"+md5Value);

  MD5能夠將字符串轉化成幾乎無衝突的hash值,可是MD5速度比較慢,MurmurHash或者JenkinsHash也能夠生成衝突不多的hash值,在Lucene的企業搜索軟件Solr1.4版本中提供了JenkinsHash實現的語義指紋,叫做Lookup3Signature。調用MurmurHash生成64位的Hash值的代碼以下所示。

public static long stringHash64(String str, int initial) {  byte[] bytes = str.getBytes();  return MurmurHash.hash64(bytes, initial);
}

  本文選自《網絡爬蟲全解析——技術、原理與實踐》,點此連接可在博文視點官網查看此書。
                    圖片描述
  想及時得到更多精彩文章,可在微信中搜索「博文視點」或者掃描下方二維碼並關注。
                       圖片描述

此外,本週正在進行一項熱門活動——《盡在雙11》阿里專家問答!
《盡在雙11》的做者樂田、仁重正經過開源問答來答覆讀者有關《盡在雙11》這本書的疑問~更多好問題,期待你來問!

相關文章
相關標籤/搜索