好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

用C#实现网络爬虫续

用C#实现网络爬虫续

上一篇 《用C#实现网络爬虫(一)》 我们实现了网络通信的部分,接下来继续讨论爬虫的实现

3. 保存页面文件

这一部分可简单可复杂,如果只要简单地把HTML代码全部保存下来的话,直接存文件就行了。

  1   private   void  SaveContents( string  html,  string   url)
   2   {
   3       if  ( string .IsNullOrEmpty(html))  //  判断html字符串是否有效 
  4       {
   5           return  ;
   6       }
   7       string  path =  string .Format( "  {0}\\{1}.txt  " , _path, _index++);  //  生成文件名 
  8  
  9       try 
 10       {
  11           using  (StreamWriter fs =  new   StreamWriter(path))
  12           {
  13              fs.Write(html);  //  写文件 
 14           }
  15       }
  16       catch   (IOException ioe)
  17       {
  18          MessageBox.Show( "  SaveContents IO  "  + ioe.Message +  "   path=  "  +  path);
  19       }
  20  
 21       if  (ContentsSaved !=  null  )
  22       {
  23          _ui.Dispatcher.Invoke(ContentsSaved, path, url);  //  调用保存文件事件 
 24       }
  25  }

第23行这里又出现了一个事件,是保存文件之后触发的,客户程序可以之前进行注册。

 1   public   delegate   void  ContentsSavedHandler( string  path,  string   url);
  2  
 3   ///   <summary> 
 4   ///   文件被保存到本地后触发
  5   ///   </summary> 
 6   public   event  ContentsSavedHandler ContentsSaved =  null ;

4. 提取页面链接

提取链接用正则表达式就能搞定了,不懂的可以上网搜。

下面的字符串就能匹配到页面中的链接

http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?

详细见代码

  1   private   string [] GetLinks( string   html)
   2   {
   3       const   string  pattern =  @"  http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?  "  ;
   4      Regex r =  new  Regex(pattern, RegexOptions.IgnoreCase);  //  新建正则模式 
  5      MatchCollection m = r.Matches(html);  //  获得匹配结果 
  6       string [] links =  new   string  [m.Count]; 
   7  
  8       for  ( int  i =  0 ; i < m.Count; i++ )
   9       {
  10          links[i] = m[i].ToString();  //  提取出结果 
 11       }
  12       return   links;
  13  }


5. 链接的过滤

不是所有的链接我们都需要下载,所以通过过滤,去掉我们不需要的链接

这些链接一般有:

已经下载的链接 深度过大的链接 其他的不需要的资源,如图片、CSS等

  1   //  判断链接是否已经下载或者已经处于未下载集合中 
  2   private   bool  UrlExists( string   url) 
   3   {
   4       bool  result =  _urlsUnload.ContainsKey(url);
   5      result |=  _urlsLoaded.ContainsKey(url);
   6       return   result;
   7   }
   8  
  9   private   bool  UrlAvailable( string   url)
  10   {
  11       if   (UrlExists(url))
  12       {
  13           return   false ;  //  已经存在 
 14       }
  15       if  (url.Contains( "  .jpg  " ) || url.Contains( "  .gif  "  )
  16          || url.Contains( "  .png  " ) || url.Contains( "  .css  "  )
  17          || url.Contains( "  .js  "  ))
  18       {
  19           return   false ;  //  去掉一些图片之类的资源 
 20       }
  21       return   true  ;
  22   }
  23  
 24   private   void  AddUrls( string [] urls,  int   depth)
  25   {
  26       if  (depth >=  _maxDepth)
  27       {
  28           return ;  //  深度过大 
 29       }
  30       foreach  ( string  url  in   urls)
  31       {
  32           string  cleanUrl = url.Trim();  //  去掉前后空格 
 33          cleanUrl = cleanUrl.TrimEnd( '  /  ' );  //  统一去掉最后面的'/' 
 34           if   (UrlAvailable(cleanUrl))
  35           {
  36               if   (cleanUrl.Contains(_baseUrl))
  37               {
  38                  _urlsUnload.Add(cleanUrl, depth);  //  是内链,直接加入未下载集合 
 39               }
  40               else 
 41               {
  42                   //   外链处理 
 43               }
  44           }
  45       }
  46  }

 第34行的 _baseUrl 是爬取的基地址,如 http://news.sina.com.cn/ ,将会保存为 news.sina.com.cn ,当一个URL包含此字符串时,说明是该基地址下的链接;否则为外链。

_baseUrl 的处理如下, _rootUr l是第一个要下载的URL

  1   ///   <summary> 
  2   ///   下载根Url
   3   ///   </summary> 
  4   public   string   RootUrl
   5   {
   6       get 
  7       {
   8           return   _rootUrl;
   9       }
  10       set 
 11       {
  12           if  (!value.Contains( "  http://  "  ))
  13           {
  14              _rootUrl =  "  http://  "  +  value;
  15           }
  16           else 
 17           {
  18              _rootUrl =  value;
  19           }
  20          _baseUrl = _rootUrl.Replace( "  www.  " ,  "" );  //  全站的话去掉www 
 21          _baseUrl = _baseUrl.Replace( "  http://  " ,  "" );  //  去掉协议名 
 22          _baseUrl = _baseUrl.TrimEnd( '  /  ' );  //  去掉末尾的'/' 
 23       }
  24  }


至此,基本的爬虫功能实现就介绍完了。

最后附上源代码和DEMO程序,爬虫的源代码在Spider.cs中,DEMO是一个WPF的程序,Test里是一个控制台的单线程版版本。

PageExtractor .rar

在下一期中,我们将介绍一些提取出网页中有效信息的方法,敬请期待。。。

 

 

标签:  爬虫 ,  C#

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于用C#实现网络爬虫续的详细内容...

  阅读:36次