1

我正在从原始URL开始抓取网页,并按照任意链接递归确定这些页面上列出的电子邮件地址。我已经使用VS2015和.net 4.6来利用抽象/简单任务提供了超线程。任务<T>对象的并行处理

我有页面下载工作递归,但仍然应用程序有一个严重的瓶颈,似乎。通过下面的简单代码,如何才能使流程更加能够并行处理每个网页,以询问电子邮件的内容以及后续的url链接?

似乎任务可能能够同时启动,以便在页面上找到的所有URL可以同时添加到循环逻辑的下一个迭代中?或做任务现在处理这个引擎盖下?

下面是我的代码,请提供一些解释,以便我可以更好地理解解决方案,因为我只是从任务开始。 (代码正在使用HTML敏捷包)

List<PageEmail> lstEmailData = new List<PageEmail>(); 

private void startButton_Click(object sender, RoutedEventArgs e) 
{ 
    getWEbData("http://localhost:801/"); //starting url 
} 

private async void getWEbData(string url) { 
    Task<string> getHTMLTask = AccessTheWebAsync(url); 
    string PageData = await getHTMLTask; 

    var html = new HtmlDocument(); 
    html.LoadHtml (PageData); 

    var emails = html.DocumentNode.SelectNodes("//a[@href]") 
     .Select(a => a.Attributes["href"].Value) 
     .Where(href => href.StartsWith("mailto:")) // keep emails, skipp links 
     .ToList(); 

    lstEmailData.Add(new PageEmail(url, emails)); 

    var urls = html.DocumentNode.SelectNodes("//a[@href]") 
    .Select(a => a.Attributes["href"].Value) 
    .Where(href => !href.StartsWith("mailto:")) // skip emails, find only url links 
    .ToList(); 

    foreach (string s in urls) { 
     getWEbData(s); 
    } 

} 

async Task<string> AccessTheWebAsync(string URL) 
{ 
    HttpClient client = new HttpClient() { MaxResponseContentBufferSize = 1000000 }; 
    Task<string> getStringTask = client.GetStringAsync(URL); 
    return await getStringTask; 
} 
+0

您可以升级到.NET 4.5吗?或者至少.NET 4.0?有更新的技术和图书馆可以提供很大的帮助,但它们只支持更新的平台。 –

+0

对不起,胖子指责说。我在Visual Studio 2015和.net 4.6 – kacalapy

+0

你当然可以将你的foreach循环变成并行构造来帮助,但是通常限制服务器允许你做多少个同步请求,所以你不会看到太多的加快你的希望。 PS一个更好的方法来处理这个问题,就是有一个队列可以去访问,例如http://blog.abodit.com/2010/03/a-simple-web-crawler-in-c-using-htmlagilitypack/ –

回答

2

核心问题可能是您受限于您无法控制的远程服务器。还有可能你受到.NET中(旧)默认连接限制的限制;在您的流程开始时尝试设置ServicePointManager.DefaultConnectionLimitint.MaxValue。除此之外,你可以做的事情不多。

由于您正在学习async,您应该知道最好避免async void。理想情况下,getWEbData应该返回Task,并且此更改允许您将“子”URL作为“子”任务处理。这对于正确传播错误特别有用:

private async void startButton_Click(object sender, RoutedEventArgs e) 
{ 
    await GetWebDataAsync("http://localhost:801/"); //starting url 
} 

private async Task GetWebDataAsync(string url) { 
    var urls = ...; 

    var urlTasks = urls.Select(s => GetWebDataAsync(s)); 
    await Task.WhenAll(urlTasks); 
} 
+0

谢谢,这有助于错误,但不'确实允许getWEbData(newURL)的多个异步操作一起运行所有单独的线程。我相信这是在最短时间内处理多个网页的最终设计。我的逻辑似乎是连续的,我希望将它移植到更加平行的位置。 – kacalapy

+0

@kacalapy:它是并发的,但不是平行的。多线程是不必要的,因为这些是I/O绑定的操作。此代码将发送无限数量的同时请求,仅受硬件,带宽和服务器端限制的限制。 –