玩玩小爬虫——入门

     前段时间做一个产品,盈利方式也就是卖数据给用户,用wpf包装一下,当然数据提供方是由公司定向爬虫采集的,虽然在实际工作

中没有接触这一块,不过私下可以玩一玩,研究研究。

    既然要抓取网页的内容,肯定我们会有一个startUrl,通过这个startUrl就可以用广度优先的方式遍历整个站点,就如我们学习数据结

构中图的遍历一样。

既然有“请求网页”和“解析网页”两部分,在代码实现上,我们得需要有两个集合,分别是Todo和Visited集合,为了简单起见,我们

从单机版爬虫说起,说起爬虫,就必然逃避不了海量数据,既然是海量数据,那么性能问题不容忽视,在Todo和Visited集合的甄别

上,我们选择用Queue和HashSet,毕竟HashSet在定位查找方面只需常量的时间,下面我们用活动图来阐述一下。

在广度优先的时候,我们需要注意两个问题:

①:有的时候网页是相对地址,我们需要转化为绝对地址。

②:剔除外链。

看看其中我们一个部门的官网,广度遍历一下,看看有多少链接,当然是剔除外链的。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Net;
  6 using System.IO;
  7 using System.Text.RegularExpressions;
  8 
  9 namespace ConsoleApplication1
 10 {
 11     public class Program
 12     {
 13         static void Main(string[] args)
 14         {
 15             var crawler = new Crawler("http://www.weishangye.com/");
 16 
 17             crawler.DownLoad();
 18 
 19             //show 一下我们爬到的链接
 20             foreach (var item in Crawler.visited)
 21             {
 22                 Console.WriteLine(item);
 23             }
 24         }
 25     }
 26 
 27     public class Crawler
 28     {
 29         //基地址
 30         public static Uri baseUri;
 31         public static string baseHost = string.Empty;
 32 
 33         /// <summary>
 34         /// 工作队列
 35         /// </summary>
 36         public static Queue<string> todo = new Queue<string>();
 37 
 38         //已访问的队列
 39         public static HashSet<string> visited = new HashSet<string>();
 40 
 41         public Crawler(string url)
 42         {
 43             baseUri = new Uri(url);
 44 
 45             //基域
 46             baseHost = baseUri.Host.Substring(baseUri.Host.IndexOf('.'));
 47 
 48             //抓取首地址入队
 49             todo.Enqueue(url);
 50         }
 51 
 52         public void DownLoad()
 53         {
 54             while (todo.Count > 0)
 55             {
 56                 var currentUrl = todo.Dequeue();
 57 
 58                 //当前url标记为已访问过
 59                 visited.Add(currentUrl);
 60 
 61                 var request = WebRequest.Create(currentUrl) as HttpWebRequest;
 62 
 63                 var response = request.GetResponse() as HttpWebResponse;
 64 
 65                 var sr = new StreamReader(response.GetResponseStream());
 66 
 67                 //提取url,将未访问的放入todo表中
 68                 RefineUrl(sr.ReadToEnd());
 69             }
 70         }
 71 
 72         /// <summary>
 73         /// 提取Url
 74         /// </summary>
 75         /// <param name="html"></param>
 76         public void RefineUrl(string html)
 77         {
 78             Regex reg = new Regex(@"(?is)<a[^>]*?href=(['""]?)(?<url>[^'""\s>]+)\1[^>]*>(?<text>(?:(?!</?a\b).)*)</a>");
 79 
 80             MatchCollection mc = reg.Matches(html);
 81 
 82             foreach (Match m in mc)
 83             {
 84                 var url = m.Groups["url"].Value;
 85 
 86                 if (url == "#")
 87                     continue;
 88 
 89                 //相对路径转换为绝对路径
 90                 Uri uri = new Uri(baseUri, url);
 91 
 92                 //剔除外网链接(获取顶级域名)
 93                 if (!uri.Host.EndsWith(baseHost))
 94                     continue;
 95 
 96                 if (!visited.Contains(uri.ToString()))
 97                 {
 98                     todo.Enqueue(uri.ToString());
 99                 }
100             }
101         }
102     }
103 }

 

当然还有很多优化的地方,既然是开篇也就这样了,快速入门才是第一位。

posted @ 2012-11-02 22:44  一线码农  阅读(11974)  评论(20编辑  收藏  举报