【问题标题】:C# Crawler Moving single thread WebClient call to multi threadingC# Crawler 将单线程 WebClient 调用移动到多线程
【发布时间】:2014-05-23 17:04:19
【问题描述】:

我们目前为无法向我们提供 xml 文件的客户使用网络爬虫。该列表正在建立,因此我需要一种更有效的方式来抓取这些站点。爬虫的逻辑很简单:

Pass in www.example.com/widgets
Store the html and pass it to crawler function

crawl widgets page 1
 IF widgets page 1 is the end of their product list
   stop
 else 
   go to widgets page 2

这对队列中的每个站点重复。如您所见,如果站点 1 有 5000 个产品,则站点 2 在完成之前无法继续。多线程的最佳方法是什么,以便我可以限制我对每个站点发出多少请求,但一次抓取多个站点?我尝试了 Parallel.ForEach,但结果非常零星且不可预测。目前,我们通过启动“组”商店并同时使用 Windows 任务管理器来处理此问题。这是一些示例代码:

foreach(site in ListofSites)
{
  int page = 1;
  bool continue_crawling = true;
  while(continue_crawling)
  {
    HtmlDocument doc = new HtmlDocument();
    var htmlWeb = new HtmlWeb();
    htmlWeb.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36";
    doc = htmlWeb.Load(URL + page);
    string html = doc.DocumentNode.OuterHtml;
    continue_crawling = ParseFile(html);
    page++;
  }
}

private bool Parse(string html)
{
  //parse the file and see if we have enough data
 return endofproduct;
}

【问题讨论】:

  • 您是想一次通过多个请求访问同一个站点,还是只在一个线程中处理每个站点(但同时访问多个站点)?
  • 我想限制我对每个站点的请求,这样我就不会压倒他们。如果我对每个站点有多个请求,一旦一个线程找到其产品列表的末尾,我将需要一种方法来停止其他线程。总体而言,最有效的就是我们要追求的目标。两者的结合甚至是一种选择。正确的数据是最重要的部分。如果我们的爬虫错过了他们产品的页面,客户会很生气。

标签: c# .net multithreading asynchronous web-crawler


【解决方案1】:

所有 C# HTTP 请求都将通过请求 URL 域的 ServicePoint。 ServicePoint 将从ServicePointManager.DefaultConnectionLimit 继承ConnectionLimit。默认值为 2,符合RFC2616 的“良好客户实践”:

单用户客户端不应与任何服务器或代理保持超过 2 个连接。

这意味着向同一个域中的 URL 发起 1 个 gazzilion HTTP 请求最多只会发送 2 个 HTTP 请求,除非一个完成,否则另一个不会启动。要获得更高的并发性,您需要增加感兴趣域的 ServicePoint 连接限制。使用线程(包括 PTL)进行并发 IO 是相当原始的,但如果您修复了限制,应该可以工作。当然,做异步 IO 会更好。

【讨论】:

  • 我必须知道何时点击产品列表结束这一事实是否会使这变得不可能?如果我向 s 站点发出 4 个请求并返回第 1-4 页,但产品的结尾是第 2 页。然后我必须通知该站点的所有其他线程在当前阅读后停止。
  • 你应该知道你爬的是什么......为什么要从askbforbinvalid url开始,你应该关注一个链接。
  • 在很多情况下这是不可能的。 url 可能不被禁止 例如,一家公司可能将小部件 a、b 和 c 混合在一起。我们可能只需要 a 所以我们会在第一个 b 出现时立即停止爬虫。另一个例子是他们在过去 6 个月内只有一个产品发布给我们。我们按发布日期排序,然后爬到 7 个月,此时我们必须在那里停止爬虫。
  • 如果你做了机会性请求,那么你可以取消它们,但你不知道它们是否已经开始发出 HTTP 请求。尽管如此,这与您的问题是正交的。我的解释显示了“我可以限制对每个站点发出多少请求,但一次抓取多个站点”已经内置到 .Net 框架中。 ServicePoint 控制节流,它们还解释了您对 TPL 使用的观察。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-19
相关资源
最近更新 更多