最近需要通过网络爬虫来收集点数据,想找一些简单易用的开源版本,总是要么配置起来有点复杂,要么功能上不太容易扩展。还是自己实现一个简单的版本更容易扩展相应的功能。这个版本的实现完全参照wiki上面对于webcrawler的架构来设计类型。
实现了一些简单的功能
- 从指定起始地址爬链接,结果以htm形式存在本地文件系统
- 执行目标输出路径和工作线程数
- 暂定和恢复爬行
- 跟踪爬行请求以及出错请求
由于只是用来收集比较少的数据,很多高级的功能没有实现,
- 没有持久化队列,程序关闭不能断点续爬
- 判断循环链接算法需要优化,目前只用了一个自定义的url树来跟踪链接
- 由于没有用图来跟踪链接,链接于链接的之间的入度关系信息丢掉了,无法应用PageRank等依赖于链接关系的算法
爬虫运行起来的样子,
输出目录
安装包和代码下载放在了Codeplex,
https://sharkcrawler.codeplex.com/
如果有人需要爬网页或者进行一些数据分析,可以直接更改这个方法SharkCrawler.Scheduler.DefaultScheduler.ThreadProc()进行相应的扩展。
private void ThreadProc()
{
string threadId = Thread.CurrentThread.Name;
TracerSink.Instance.Trace(threadId, string.Empty, "Started");
while (!stop)
{
if (!pause)
{
string uri = null;
lock (queuelock)
{
if (queue.Count > 0)
{
uri = queue.Dequeue();
}
}
if (!string.IsNullOrEmpty(uri))
{
TracerSink.Instance.Trace(threadId, uri, "Downloading");
WebPage page = WebPageDownloader.Download(uri);
if (page != null)
{
fileStorage.SaveWebPage(page);
Collection<string> urls = HtmlParser.ParseUrl(page.Content);
lock (queuelock)
{
for (int i = 0; i < urls.Count; i++)
{
string url = urls[i].Substring(6, urls[i].Length - 7);
if (!queue.Contains(url)
&& url.StartsWith("http")
&& !url.Contains("?")
&& (url.EndsWith("/")
|| url.EndsWith(".htm")
|| url.EndsWith(".html")
|| url.EndsWith(".aspx")
|| url.EndsWith(".asp")
|| url.EndsWith(".jsp")
|| url.EndsWith(".php")
|| url.LastIndexOf('.') < url.LastIndexOf('/'))
)
{
queue.Enqueue(url);
}
}
}
}
}
else
{
TracerSink.Instance.Trace(threadId, string.Empty, "Sleeping");
Thread.Sleep(100);
}
}
else
{
TracerSink.Instance.Trace(threadId, string.Empty, "Paused");
Thread.Sleep(500);
}
}
TracerSink.Instance.Trace(threadId, string.Empty, "Stopped");
}