GJM:用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的处理如下,_rootUrl是第一个要下载的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里是一个控制台的单线程版版本。
百度云网盘 链接:http://pan.baidu.com/s/1pKMfI8F 密码:3vzh
GJM :于 2016-11-16 转载自 http://www.cnblogs.com/Jiajun/archive/2012/06/17/2552458.html 如影响作者版权问题 请联系我 993056011@163.com
在下一期中,我们将介绍一些提取出网页中有效信息的方法,敬请期待。。。
GJM:用C#实现网络爬虫(二) [转载]的更多相关文章
- Python初学者之网络爬虫(二)
声明:本文内容和涉及到的代码仅限于个人学习,任何人不得作为商业用途.转载请附上此文章地址 本篇文章Python初学者之网络爬虫的继续,最新代码已提交到https://github.com/octans ...
- NodeJs 入门到放弃 — 常用模块及网络爬虫(二)
码文不易啊,转载请带上本文链接呀,感谢感谢 https://www.cnblogs.com/echoyya/p/14473101.html 目录 码文不易啊,转载请带上本文链接呀,感谢感谢 https ...
- Python网络爬虫(二)
Urllib库之解析链接 Urllib库里有一个parse这个模块,定义了处理URL的标准接口,实现 URL 各部分的抽取,合并以及链接转换.它支持如下协议的 URL 处理:file.ftp.goph ...
- 【Python网络爬虫二】使用urllib2抓去网页内容
在Python中通过导入urllib2组件,来完成网页的抓取工作.在python3.x中被改为urllib.request. 爬取具体的过程类似于使用程序模拟IE浏览器的功能,把URL作为HTTP请求 ...
- Python网络爬虫与如何爬取段子的项目实例
一.网络爬虫 Python爬虫开发工程师,从网站某一个页面(通常是首页)开始,读取网页的内容,找到在网页中的其它链接地址,然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页 ...
- GJM:用C#实现网络爬虫(一) [转载]
网络爬虫在信息检索与处理中有很大的作用,是收集网络信息的重要工具. 接下来就介绍一下爬虫的简单实现. 爬虫的工作流程如下 爬虫自指定的URL地址开始下载网络资源,直到该地址和所有子地址的指定资源都下载 ...
- 【网络爬虫】【java】微博爬虫(二):如何抓取HTML页面及HttpClient使用
一.写在前面 上篇文章以网易微博爬虫为例,给出了一个很简单的微博爬虫的爬取过程,大概说明了网络爬虫其实也就这么回事,或许初次看到这个例子觉得有些复杂,不过没有关系,上篇文章给的例子只是让大家对爬虫过程 ...
- SHELL网络爬虫实例剖析--转载
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://nolinux.blog.51cto.com/4824967/1552472 前天 ...
- Golang 网络爬虫框架gocolly/colly 二 jQuery selector
Golang 网络爬虫框架gocolly/colly 二 jQuery selector colly框架依赖goquery库,goquery将jQuery的语法和特性引入到了go语言中.如果要灵活自如 ...
随机推荐
- jQuery LigerUI 最新版压缩包(含chm帮助文档、源码、donet权限示例)
jQuery LigerUI 最新版压缩包 http://download.csdn.net/download/heyin12345/4680593 jQuery LigerUI 最新版压缩包(含ch ...
- ASP.NET常用的SqlDbHelper类
请引用 using System.Data;using System.Data.SqlClient; 两个命名空间. 可以满足常用的数据集,读取多条数据,以及增删改操作 代码: /// <sum ...
- 【WP 8.1开发】上下文菜单
在桌面系统中,别说是开发者,相信有资格考得过计算机一级的人都知道什么叫一下文菜单,或者叫右键菜单. 为了让操作更方便,在手机应用程序中,也应当有这样的菜单.上下文菜单之所以有”上下文“之说,是因为通常 ...
- Android之自动文本输入识别提示
相信大家都熟悉自动识别提示吧,在我们的生活中随处可见,今天就让我为大家简单介绍一下它是如何设计的. 所谓自动识别输入即是根据用户输入的已有信息,为用户提示可能的值,方便用户完成输入.在Android设 ...
- 编译原理LL1文法分析树(绘图过程)算法实现
import hjzgg.analysistable.AnalysisTable; import hjzgg.first.First; import hjzgg.follow.Follow; impo ...
- js断点调试心得
虽然网上已经有多的数不清的调试教程了,但仍然没有发现哪篇文章写的通俗易懂,索性自己尝试写写自己的一些使用习惯或者说是心得,希望对那些还不是很懂得使用断点调试的孩子有一些帮助(大神请无视~). 1.断点 ...
- [Node.js] DSL in action
原文地址:http://www.moye.me/2015/05/30/dsl-in-action/ 最近看了本有意思的书,受到了一些启发,在此记录一下: DSLs in action DSL是什么 ...
- Windows Azure Cloud Service (37) 浅谈Cloud Service
<Windows Azure Platform 系列文章目录> 最近在和一些客户聊天,常常被遇到这样的问题: 1.问题一:我在创建一个新的Windows Azure Virtual Mac ...
- C#根据身份证号码,计算生日、年龄、性别
朋友谈及身份证相关的信息,才了解到原来省份证号码中包含了年龄和性别. 这样在数据库中,就不必单独留字段存放它们了(不过,要根据具体情况来,要是读取频率较高,还是单独列出为好),这样顺带解决了年龄变更的 ...
- SQL Server安全(9/11):透明数据加密(Transparent Data Encryption)
在保密你的服务器和数据,防备当前复杂的攻击,SQL Server有你需要的一切.但在你能有效使用这些安全功能前,你需要理解你面对的威胁和一些基本的安全概念.这篇文章提供了基础,因此你可以对SQL Se ...