2010-01-05 43 views
0

我正在写C#中的一个爬虫,它以一组已知的url在文件中开始。我想把页面拉下来。我的问题是什么是最好的模式,即读取文件到列表/数组的URL,创建一个数组来存储完成的URL?我应该创建一个2维数组来跟踪线程的状态和完成吗?还有一些其他的考虑因素是重试(如果第一个请求很慢或者死机)或者自动重启(应用/系统崩溃)。Asynch Design C#

回答

1
foreach (var url in File.ReadAllLines("urls.txt")) 
{ 
    var client = new WebClient(); 
    client.DownloadStringCompleted += (sender, e) => 
    { 
     if (e.Error == null) 
     { 
      // e.Result will contain the downloaded HTML 
     } 
     else 
     { 
      // some error occurred: analyze e.Error property 
     } 
    }; 
    client.DownloadStringAsync(new Uri(url)); 
} 
+0

Ouch。一举解决所有的请求并不会很好。如果列表足够大,则会出现多个故障点,包括此时超时,路由器超负荷,端口耗尽等等。这些请求将需要*排程以超越玩具爬行器。 – spender 2010-01-05 14:59:40

+0

然后只需使用一个ThreadPool。 – 2010-01-05 19:00:52

0

这里是我的关于存储数据

我会建议你使用relationnal数据库,用于存储网页列表,因为它会让你的工作更加容易进行意见:

  • 检索要抓取的页面(基本上是具有最早的SuccessFullCrawlDate的N个页面)
  • 添加新发现的页面
  • 页标记为已爬(设置SuccessFullCrawlDate标志)
  • 程序崩溃的情况下,你的数据就已经是安全的
  • 您可以添加列来存储的重试次数,自动抛弃那些比失败更N次...

关系模型的一个例子是:

//this would contain all the crawled pages 
table Pages { 
    Id bigint, 
    Url nvarchar(2000) 
    Created DateTime, 
    LastSuccessfullCrawlDate DateTime, 
    NumberOfRetry int //increment this when a failure occures, if it reach 10 => set Ignored to True 
    Title nvarchar(200) //this is is where you would put the html 
    Content nvarchar(max) //this is is where you would put the html 
    Ignored Bool,   //set it to True to ignore this page 
} 

你也可以处理的Referer与王氏这种结构的表格:

//this would contain all the crawled pages 
table Referer { 
    ParentId bigint, 
    ChildId bigint 
} 

它可以让你实现你自己的网页排名:P

+0

在db中存储元数据可能是最有意义的。实际的html内容应该存储在文件系统中。我正在使用mysql。 – traderde 2010-01-08 12:34:51

1

我建议你从队列中拉出,并在一个单独的线程获取每个URL,从队列中脱落,直到你最大出你想允许的simultaenous线程的数量。每个线程调用一个回调方法,报告它是否成功完成或遇到问题。

当您启动每个线程时,将其ManagedThreadId放入一个字典中,其中键为id,值为线程状态。回调方法应该返回它的id和完成状态。从Dictionary中删除每个线程,并完成下一个等待线程。如果未成功完成,则将其添加回队列。

Dictionary的Count属性告诉你有多少个线程在运行,回调也可以用来更新你的UI或检查暂停或暂停信号。如果您在系统崩溃时需要保留结果,那么您应该考虑使用数据库表来代替内存驻留集合,例如Manitra描述的。

这种方法对我来说很适合大量的并发线程。

+0

谢谢,这是我正在思考的实现。调度和线程/请求限制肯定是需要的。 – traderde 2010-01-08 12:33:04

+0

很高兴为您提供帮助。如果这样做对你来说,那么请标记为已回答。 – 2010-01-13 23:14:23