前段时间做一个产品,盈利方式也就是卖数据给用户,用wpf包装一下,当然数据提供方是由公司定向爬虫采集的,虽然在实际工作
中没有接触这一块,不过私下可以玩一玩,研究研究。
既然要抓取网页的内容,肯定我们会有一个startUrl,通过这个startUrl就可以用广度优先的方式遍历整个站点,就如我们学习数据结
构中图的遍历一样。
既然有“请求网页”和“解析网页”两部分,在代码实现上,我们得需要有两个集合,分别是Todo和Visited集合,为了简单起见,我们
从单机版爬虫说起,说起爬虫,就必然逃避不了海量数据,既然是海量数据,那么性能问题不容忽视,在Todo和Visited集合的甄别
上,我们选择用Queue和HashSet,毕竟HashSet在定位查找方面只需常量的时间,下面我们用活动图来阐述一下。
在广度优先的时候,我们需要注意两个问题:
①:有的时候网页是相对地址,我们需要转化为绝对地址。
②:剔除外链。
看看其中我们一个部门的官网,广度遍历一下,看看有多少链接,当然是剔除外链的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
public class Program
{
static void Main(string[] args)
{
var crawler = new Crawler("http://www.weishangye.com/");
crawler.DownLoad();
//show 一下我们爬到的链接
foreach (var item in Crawler.visited)
{
Console.WriteLine(item);
}
}
}
public class Crawler
{
//基地址
public static Uri baseUri;
public static string baseHost = string.Empty;
/// <summary>
/// 工作队列
/// </summary>
public static Queue<string> todo = new Queue<string>();
//已访问的队列
public static HashSet<string> visited = new HashSet<string>();
public Crawler(string url)
{
baseUri = new Uri(url);
//基域
baseHost = baseUri.Host.Substring(baseUri.Host.IndexOf('.'));
//抓取首地址入队
todo.Enqueue(url);
}
public void DownLoad()
{
while (todo.Count > 0)
{
var currentUrl = todo.Dequeue();
//当前url标记为已访问过
visited.Add(currentUrl);
var request = WebRequest.Create(currentUrl) as HttpWebRequest;
var response = request.GetResponse() as HttpWebResponse;
var sr = new StreamReader(response.GetResponseStream());
//提取url,将未访问的放入todo表中
RefineUrl(sr.ReadToEnd());
}
}
/// <summary>
/// 提取Url
/// </summary>
/// <param name="html"></param>
public void RefineUrl(string html)
{
Regex reg = new Regex(@"(?is)<a[^>]*?href=(['""]?)(?<url>[^'""\s>]+)\1[^>]*>(?<text>(?:(?!</?a\b).)*)</a>");
MatchCollection mc = reg.Matches(html);
foreach (Match m in mc)
{
var url = m.Groups["url"].Value;
if (url == "#")
continue;
//相对路径转换为绝对路径
Uri uri = new Uri(baseUri, url);
//剔除外网链接(获取顶级域名)
if (!uri.Host.EndsWith(baseHost))
continue;
if (!visited.Contains(uri.ToString()))
{
todo.Enqueue(uri.ToString());
}
}
}
}
}
当然还有很多优化的地方,既然是开篇也就这样了,快速入门才是第一位。
时间: 2024-10-28 11:03:26