[原创]通过Url对页面进行抓取----爬虫程序(一)

最近做毕设的时候,指导老师说现有的资料不够,项目负责人要求去某某高校的图书馆上抓些FAQ的信息回来帮助筛选...于是我又有了新任务--写个爬虫程序.
不过由于是针对某个网站抽出页面特定内容,所以可以写的比较有针对性,减少了很多适应性的要求.我也经过对爬虫从0起点的学习和自己编写代码,终于完成了任务.下面让我来一步一步总结一下吧.

其实,C#特别适合于构造蜘蛛程序,这是因为它已经内置了HTTP访问和多线程的能力,而这两种能力对于蜘蛛程序来说都是非常关键的。下面是我构造这个针对性爬虫程序要解决的关键问题:

  1. 页面处理:需要处理每一个下载得到的页面。下载得到的内容可能要保存到磁盘,或者进一步分析处理。
  2. HTML分析:可能需要某种HTML解析器来分析蜘蛛程序遇到的每一个页面。
  3. 多线程:只有拥有多线程能力,蜘蛛程序才能真正做到高效。
  4. 确定何时完成:不要小看这个问题,确定任务是否已经完成并不简单,尤其是在多线程环境下。

让我们先来看页面处理,爬虫的特点是下载一个页面找寻url连接,接着去下一个页面的寻找并下载,让我们通过转化思想把问题缩小如下:

  1. 得到一个页面,分析页面内容,得到新的url,存进存储介质备用;
  2. 下好一个页面从储存介质中取新页面url,重复第一步;

现在发现了吧,基础问题就是通过url对一个页面的下载,用C#语言来实现的话将非常非常简单,需要一个url参数,使用到三个基础类库HttpWebRequest、HttpWebResponse、StreamReader,使用的头文件加上System.IO,System.Net(或Web),通过发送Http请求,接受响应,和接受数据流文件存入你想存入的储存介质(可以是内存,文件,甚至数据库),就完成了一个页面的下载,是不是很简单.

这是最精简的代码了,如果出错查下ex吧.

try
{
WebRequest request = WebRequest.Create("http://www.baidu.com/");
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("gb2312"));
tb.Text = reader.ReadToEnd();

reader.Close();
reader.Dispose();
response.Close();
}
catch (Exception ex)
{
String Text = ex.Message;
}
 

 

我对这个部分进行了"修饰",包括—1.使用了基于Http协议的类库,并非上述代码中的WebRequest;2.页面不同编码的处理(主要是消除中文乱码的问题);3.大页面的截取(如果你用上述代码区请求163或sina等大型门户的主页,会卡上好久甚至响应超时,因为页面内容多代码比较大);本地写入的缓冲设置等等...其中为了消除中文乱码和封装这部分操作,我采用了2个返回值,用无类型数组,可以看下:

/// <summary>
///
获取Html页面内容
/// </summary>
/// <param name="url">
页面url地址
</param>
/// <returns>
页面内容string,编码代号
</returns>
private object[] GetResponse(string url)
{
string html = string.Empty;
string encodingType = string.Empty;
byte[] buffer = new byte[2048];
//缓冲器
//2个返回值
object[] obj = new object[2];
obj[1] = "gb2312";
//默认解码
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "get";
request.ContentType = "text/html";
request.Timeout = 15000;//设置请求超时,单位毫秒
request.UseDefaultCredentials = false;
//获取或设置一个 System.Boolean 值,该值控制 System.Net.CredentialCache.DefaultCredentials
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

using (Stream reader = response.GetResponseStream())
{
using (MemoryStream memo = new MemoryStream())
{
int index = 1;
int sum = 0;
//限制读取不超过100K,大页面截取100k,可以正常浏览的
while (index > 0 && sum < 100 * 1024)
{//对流文件写入设置1K的缓存
index = reader.Read(buffer, 0, buffer.Length);
if (index > 0)
{
memo.Write(buffer, 0, index);
sum += index;
}
}

html = Encoding.GetEncoding("gb2312").GetString(memo.ToArray());
//解析Html编码charset值
if (string.IsNullOrEmpty(html))
{
obj[0] = html;
return obj;
}
else
{//正则截取页面头文件
Regex reg = new Regex(@"charset=(?<charset>[\s\S]*?)""");
Match m = reg.Match(html.ToLower());
encodingType = m.Groups["charset"].ToString();
}
if (string.IsNullOrEmpty(encodingType) || string.Equals(encodingType, "gb2312"))
{
obj[0] = html;
return obj;
}
else
//不是gb2312的重新编码
{
obj[0] = Encoding.GetEncoding(encodingType).GetString(memo.ToArray());
obj[1] = encodingType;
return obj;
//return Encoding.GetEncoding(encodingType).GetString(memo.ToArray());
}
}
}
}
catch (Exception ex)
{
ex.ToString();
return obj;
}
}

返回的数组内2个返回值是页面html代码的string和编码信息,如:UTF-8,GB2312等,来区分对html代码操作时用哪种编码.

posted @ 2009-03-31 17:58  梳子  阅读(3325)  评论(1编辑  收藏  举报