網絡爬蟲-url索引

網絡爬蟲-url索引

http://www.cnblogs.com/yuandong/archive/2008/08/28/Web_Spider_Url_Index.htmlhtml

url索引的做用是判斷一個url是否被抓取過,採用的算法主要是MD5數字簽名。算法

假設一共要抓取的url不超過1億條,用一個二進制的位表示一個url是否被抓取過,則至少須要1億個位,咱們管每個位叫一個「槽」。考慮到MD5的算法是可能出現衝突(即不一樣的url算出來的MD5可能相同,這種機率很小),槽越少,衝突越明顯,因此槽越多越好。但另外一方面,還要考慮到佔用內存的大小,由於在抓取的過程當中,爲了保證效率,全部的槽都須要載入內存。目前我使用的是2的28次方,即32M,至關於268435456(2.6億)個槽。數組

當要判斷一個url是否已經抓取過的時候,只要判斷該url通過MD5簽名後的值所對應的槽是否標記爲1便可。例如給出的url是:http://www.ouc.edu.cn/,通過128位的MD5簽名後,得出的1073542761,則須要判斷的就是第1073542761個槽是0仍是1。一樣的道理,當完成一個url的抓取後,要將對應的槽標記爲1。網絡

存儲槽的32M空間在內存是不連續的,由於操做系統很難劃分出32M的連續內存空間,因此將其分爲4096個段Segment,每段2048個32位整數,32*2048*4096=268435456。至關於一個整型的二維數組。ide

url

咱們使用32位的MD5做爲簽名,表示爲一個整數。這個整數分爲三部分,分別是段地址、段偏移和值地址。第5-16位表示段地址,17-27位表示段偏移,28-32位(最後5位,取值範圍爲2的5次方,即0-31)表示在整形值中的位置、即值地址。函數

url2

當給定一個url的MD5值時,經過如下函數計算出其段地址:url

   1:  unsigned short get_segment_index(unsigned int md5) {
   2:      
   3:      //5-16位表示段地址
   4:      
   5:      unsigned short result;
   6:      bzero(&result, sizeof(unsigned short));
   7:      memcpy(&result, ((char*)&md5) + 2, sizeof(unsigned short));
   8:   
   9:      return result & 0x0FFF;
  10:  }

經過如下函數計算出其段偏移:spa

   1:  unsigned short get_segment_offset(unsigned int md5) {
   2:      
   3:      //17-27位表示段偏移
   4:      
   5:      unsigned short result;
   6:      bzero(&result, sizeof(unsigned short));
   7:      memcpy(&result, ((char*)&md5), sizeof(unsigned short));
   8:   
   9:      return result >> 5;
  10:  }

經過如下函數計算其值偏移:操作系統

   1:  unsigned int get_value(unsigned int md5) {
   2:      
   3:      //28-32(最後5位)爲表示值
   4:      
   5:      unsigned int result = 1;
   6:      return result << (md5 & 0x0000001F);
   7:  }

再獲得段地址、段偏移和值偏移後,就經過一下函數斷定該Url是否已被抓取:code

   1:  bool is_url_crawled(char* url) {
   2:   
   3:      //將給出的url進行md5運算,取得對應的Value,於儲存的Value按位與
   4:      
   5:      unsigned int url_md5 = md5(url);
   6:      unsigned short segment_index = get_segment_index(url_md5);
   7:      unsigned short segment_offset = get_segment_offset(url_md5);
   8:      unsigned int value = get_value(url_md5);
   9:      
  10:      unsigned int result = (unsigned int)
                                 (url_index[segment_index][segment_offset] & value);
  11:   
  12:      return result > 0 ? TRUE : FALSE;
  13:  }

若是未被抓取,在完成抓取後,經過如下函數標記爲已抓取:

   1:  int mark_url_as_crawled(char* url) {
   2:   
   3:      //取得段地址、段偏移和url對應的值
   4:      unsigned int url_md5 = md5(url);
   5:      unsigned short segment_index = get_segment_index(url_md5);
   6:      unsigned short segment_offset = get_segment_offset(url_md5);
   7:      unsigned int value = get_value(url_md5);
   8:   
   9:      //經過按位或標記url對應的位爲已抓取
  10:      url_index[segment_index][segment_offset] |= value;
  11:      
  12:      //同步寫入索引文件
  13:      value = url_index[segment_index][segment_offset];
  14:      long offset = (((long)segment_index) * SEGMENT_LENGTH + segment_offset) 
                            * sizeof(unsigned int);
  15:      if(fseek(index_file, offset, SEEK_SET) != 0)
  16:          return -1;
  17:      
  18:      if(fwrite(&value, sizeof(unsigned int), 1, index_file) != 1)
  19:          return -1;    
  20:      
  21:      fflush(index_file);
  22:      return 0;
  23:  }
相關文章
相關標籤/搜索