简易网络爬虫程序的开发(c#版)收藏
给大家共享下自己写的一个简易网络爬虫程序,本程序分为两部分:spider 程
序集与 spiderserver windows 服务程序,其中 spider 程序对爬虫程序的线程管
理与获取网页的 html 做了封装。先看看这个程序的类图吧:
下面我对这些类一一介绍:
HttpServer 类
该类中只有一个方法 public string GetResponse(string url)功能是对指定的
url 获取该页面的 html,实现该功能必须解决以下几个问题:
1.如何获取指定 url 的 html?
其实实现该功能很简单,在 C#中通过 HttpWebResponse 类的调用就能实现,具体
方法是:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream reader = response.GetResponseStream();
然后从 reader 流中读取内容就行了
2.编码问题,网页通常使用 utf-8 或 gb2312 进行编码,如果程序在读取流时使
用了错误的编码会导致中文字符的错误
为解决这个问题我先看一小段某网页的 html
百度一下,你就知道
在标签中会指定该页面的编码:charset=gb2312,所以我的程序中要先读
取 charset 的值,然后再重新按 charset 的值对读流进行读取,为了使这个过程
更加简单,我先统一按"gb2312"进行编码,从流中读取 html,在分析 html 的
charset 值,如果该值也是"gb2312"就直接返回 html,如果是其它编码就重新
读取流。
3.对于有些页面的 html 可能会非常大所以我们要限制大小,在程序中最在读取
不会超过 100k
该类完整代码如下:
///
/// HTTP 服务类
///
internal class HttpServer
{
///
/// 获取指定页面 html 文本
///
/// 页面 url
public string GetResponse(string url)
{
try
{
string html = string.Empty;
string encoding = string.Empty;
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(url);
request.Method = "get";
request.ContentType = "text/html";
byte[] buffer = new byte[1024];
using (HttpWebResponse response =
(HttpWebResponse)request.GetResponse())
response.GetResponseStream())
memory = new MemoryStream())
{
using (Stream reader =
{
using (MemoryStream
{
小不超过 100k
0 && sum < 100 * 1024)
= reader.Read(buffer, 0, 1024);
(index > 0)
memory.Write(buffer, 0, index);
sum += index;
int index = 1;
int sum = 0;
//限制的读取的大
while (index >
{
index
if
{
}
}
html =
Encoding.GetEncoding("gb2312").GetString(memory.ToArray());
(string.IsNullOrEmpty(html))
html;
if
{
return
charset 的值
re = new Regex(@"charset=(?[\s\S]*?)""");
m = re.Match(html.ToLower());
ng = m.Groups["charset"].ToString();
}
else
{
}
if
//解析
Regex
Match
encodi
(string.IsNullOrEmpty(encoding) || string.Equals(encoding.ToLower(),
"gb2312"))
html;
gb2312 编码则按 charset 值的编码进行读取
{
}
else
{
return
//不是
return
Encoding.GetEncoding(encoding).GetString(memory.ToArray());
}
}
}
}
return "";
}
catch
{
}
}
}
}
由于在程序外该类是不可见的,所以声明时用了 internal.
AbsChain 类
对于 AbsChain 采用的是职责链设计模式,目的是抽象出网络爬虫处理 html 的过
程,因为在 spider 程序集中并不真正处理如何解析 html,用户只需重载 AbsChain
类中的 process 方法,完成自定义的处理过程
程序源码如下:
namespace WebSpider
{
///
/// 职责链抽象类
///
public abstract class AbsChain
{
private AbsChain _handler=null;
private string _url = string.Empty;
public string Url { get { return _url; } set { _url =
value; } }
internal AbsChain Handler
{
get
{
}
}
return _handler;
///
/// 文本处理过程
///
///
html 文本
protected abstract void Process(string html);
///
/// 设置下一个处理节点
///
///
下一个处理节点
public void SetProcessHandler(AbsChain handler)
{
_handler = handler;
}
///
/// 开始处理
///
///
html 文本流
public void Start(string html)
{
Process(html); //处理用户重载方法
if (Handler != null)
{
Handler.Url = Url;
Handler.Start(html);
}
}
}
}
ChainMain 类:
ChainMain 类是对 AbsChain 类的具体实现,但是它的 Process 方法是个空方法,
所以你可以把它理解成它就是具体处理职责链上的头 节点,通过 ChainMain 类
的_handler 将处理任务往下传递,用户通过调用 ChainMain 的
SetProcessHandler 方法设置下 一个处理节点,这个节点必须由用户继承
AbsChain 并实现抽象方法 Process。ChainMain 类的源代码如下:
namespace WebSpider
{
internal class ChainMain : AbsChain
{
protected override void Process(string html)
{
}
}
}
WorkThread 类:
WorkThread 类是工作线程类,每个工作线程类都包括一个职责链的头节点
ChainMain、一个 HttpServer 类和一个 UrlStack,其中 UrlStack 类采用了单构
件设计模式,所以对于整个应该用程序都是使用一个 UrlStack 对象。
源代码如下:
namespace WebSpider
{
///
/// 工作线程
///
internal class WorkThread
{
private ChainMain _chainHeader = new ChainMain();
private HttpServer _httpServer = new HttpServer();
private bool _isRun = false;
///
/// 职责链的头节点
///
public ChainMain ChainMain
{
get
{
}
}
return _chainHeader;
public HttpServer HttpServer
{
get
{
}
}
return _httpServer;
public bool IsRun { get { return _isRun; } }
public UrlStack UrlStack
{
get
{
}
}
return UrlStack.Instance;
///
/// 工作线程入口函数
///
///
种子 url
public void Start()
{
try
{
_isRun = true;
while (_isRun)
{
_httpServer.GetResponse(url);
(!string.IsNullOrEmpty(html))
= url;
t(html);
//从地址堆栈中取出 url
string url = UrlStack.Pop();
if (!string.IsNullOrEmpty(url))
{
string html =
if
{
}
ChainMain.Url
ChainMain.Star
}
}
}
catch
{
}
}
///
/// 停止工作线程
///
public void Stop()
{
_isRun = false;
}
}
}
Start 方法是工作线程的入口方法,它从 UrlStack 中取出 url,并调用
HttpServer 的 GetResponse 方法取出 Url 对应 网页的 HTML 代码,并将 HTML 代
码传递给职责链的头节点 ChainMain,由它的 Start 方法开始处理。回忆一下
AbsChain 的 Start()方法,它是先调用自身类的 Process 方法,然后再调用
_handler.Start()方法,就这样把处理过程传递下去。
UrlStack 类: