1、网络爬虫在信息检索与处理中有很大的作用,是收集网络信息的重要工具。接下来就介绍一下爬虫的简单实现。爬虫的工作流程如下爬虫自指定的 URL 地址开始下载网络资源,直到该地址和所有子地址的指定资源都下载完毕为止。下面开始逐步分析爬虫的实现。1. 待下载集合与已下载集合为了保存需要下载的 URL,同时防止重复下载,我们需要分别用了两个集合来存放将要下载的 URL 和已经下载的URL。因为在保存 URL 的同时需要保存与 URL 相关的一些其他信息,如深度,所以这里我采用了 Dictionary 来存放这些URL。具体类型是 Dictionary 其中 string 是 Url 字符串,int 是该
2、Url 相对于基 URL 的深度。每次开始时都检查未下载的集合,如果已经为空,说明已经下载完毕;如果还有 URL,那么就取出第一个 URL 加入到已下载的集合中,并且下载这个 URL 的资源。2. HTTP 请求和响应C#已经有封装好的 HTTP 请求和响应的类 HttpWebRequest 和 HttpWebResponse,所以实现起来方便不少。为了提高下载的效率,我们可以用多个请求并发的方式同时下载多个 URL 的资源,一种简单的做法是采用异步请求的方法。控制并发的数量可以用如下方法实现1 private void DispatchWork()2 3 if (_stop) /判断是否中止
3、下载4 5 return;6 7 for (int i = 0; i 0)22 23 MemoryStream ms = new MemoryStream(rs.Data, 0, read); /利用获得的数据创建内存流24 StreamReader reader = new StreamReader(ms, _encoding);25 string str = reader.ReadToEnd(); /读取所有字符26 rs.Html.Append(str); / 添加到之前的末尾27 var result = resStream.BeginRead(rs.Data, 0, rs.Buffe
4、rSize, /再次异步请求读取数据28 new AsyncCallback(ReceivedData), rs);29 return;30 31 html = rs.Html.ToString();32 SaveContents(html, url); /保存到本地33 string links = GetLinks(html); /获取页面中的链接34 AddUrls(links, depth + 1); /过滤链接并添加到未下载集合中35 36 _reqsBusyindex = false; /重置工作状态37 DispatchWork(); /分配新任务38 39 catch (Web
5、Exception we)40 41 MessageBox.Show(“ReceivedData Web “ + we.Message + url + we.Status);42 43 第 14 行获得了读取的数据大小 read,如果 read0 说明数据可能还没有读完,所以在 27 行继续请求读下一个数据包;如果 read4 / 全部链接下载分析完毕后触发5 / 6 public event DownloadFinishHandler DownloadFinish = null;3. 保存页面文件这一部分可简单可复杂,如果只要简单地把 HTML 代码全部保存下来的话,直接存文件就行了。1 p
6、rivate void SaveContents(string html, string url)2 3 if (string.IsNullOrEmpty(html) /判断 html 字符串是否有效4 5 return;6 7 string path = string.Format(“01.txt“, _path, _index+); /生成文件名8 9 try10 11 using (StreamWriter fs = new StreamWriter(path)12 13 fs.Write(html); /写文件14 15 16 catch (IOException ioe)17 18
7、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 / 4 / 文件被保存到本地
8、后触发5 / 6 public event ContentsSavedHandler ContentsSaved = null;4. 提取页面链接提取链接用正则表达式就能搞定了,不懂的可以上网搜。下面的字符串就能匹配到页面中的链接http:/(w-+.)+w-+(/w- ./?%4 Regex r = new Regex(pattern, RegexOptions.IgnoreCase); /新建正则模式5 MatchCollection m = r.Matches(html); /获得匹配结果6 string links = new stringm.Count; 7 8 for (int i
9、 = 0; i = _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 else41 42 /
10、外链处理43 44 45 46 第 34 行的_baseUrl 是爬取的基地址,如 http:/ ,当一个 URL 包含此字符串时,说明是该基地址下的链接;否则为外链。_baseUrl 的处理如下,_rootUrl 是第一个要下载的 URL1 / 2 / 下载根 Url3 / 4 public string RootUrl5 6 get7 8 return _rootUrl;9 10 set11 12 if (!value.Contains(“http:/“)13 14 _rootUrl = “http:/“ + value;15 16 else17 18 _rootUrl = value;19 20 _baseUrl = _rootUrl.Replace(“www.“, “); /全站的话去掉 www21 _baseUrl = _baseUrl.Replace(“http:/“, “); /去掉协议名22 _baseUrl = _baseUrl.TrimEnd(/); /去掉末尾的 /23 24 至此,基本的爬虫功能实现就介绍完了。