用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测试数据.cn/ ,将会保存为 news.sina测试数据.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( " HdhCmsTest " , "" ); // 全站的话去掉www
21 _baseUrl = _baseUrl.Replace( " http:// " , "" ); // 去掉协议名
22 _baseUrl = _baseUrl.TrimEnd( ' / ' ); // 去掉末尾的'/'
23 }
24 }
至此,基本的爬虫功能实现就介绍完了。
最后附上源代码和DEMO程序,爬虫的源代码在Spider.cs中,DEMO是一个WPF的程序,Test里是一个控制台的单线程版版本。
PageExtractor .rar
在下一期中,我们将介绍一些提取出网页中有效信息的方法,敬请期待。。。
标签: 爬虫 , C#
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息