【发布时间】:2020-01-01 01:29:28
【问题描述】:
我正在尝试使用 HtmlAgilityPack 解析 html 页面以从中提取链接,然后将链接添加到 ListBox,然后将链接从 listBox 添加到队列。
我有三个任务(PageParse、AddItemsToList、EnqueueFromList)
好的我的问题是当我单击按钮时整个应用程序都挂起。
按钮代码
private void CrawdBtn_Click(object sender, EventArgs e)
{
t = Task.Factory.StartNew(PageParse);
t.Wait();
TaskAddToList = Task.Factory.StartNew(() => AddItemsToList(t.Result));
TaskAddToList.Wait();
b = new Task(EnqueueFromList);
b.Start();
//Task.WaitAll(t,b);
CrawdBtn.Enabled = true;
}
页面解析方法
public HtmlAgilityPack.HtmlDocument PageParse()
{
MessageBox.Show($"Page Parse Has started");
web = new HtmlWeb();
doc = new HtmlAgilityPack.HtmlDocument();
doc = web.Load(UrlText.Text);
return doc;
}
将项目添加到列表代码
private void AddItemsToList(HtmlAgilityPack.HtmlDocument doc)
{
foreach (HtmlNode Node in doc.DocumentNode.SelectNodes("//a[@href]"))
{
HtmlAttribute att = Node.Attributes["href"];
listBox1.Invoke(new AddToListDelegate(AddToList), att.Value);
Thread.Sleep(1000);
}
}
我通过以下断点注意到调试器在执行 PageParse 方法时挂起
【问题讨论】:
-
Wait()使整个过程同步。 (顺便说一句,为什么TaskFactory.StartNew()而不是Task.Run()?)。您需要将事件处理程序设为async,然后当方法的本机异步版本不可用时,您可以使用Task.Run()调用异步方法。例如,将此添加到您的Button.Click异步处理程序:var doc = await GetDocumentAsync(url);并添加这两个方法:internal HtmlAgilityPack.HtmlDocument GetDocument(string url) => new HtmlWeb().Load(url);和internal Task<HtmlAgilityPack.HtmlDocument> GetDocumentAsync(string url) => Task.Run(() => GetDocument(url)); -
当然,您可以将这些任务添加到
List<Task<HtmlAgilityPack.HtmlDocument>>,然后再添加到var docs = await Task.WhenAll([Your List Of Tasks]);。docs将包含所有 HtmlDocument 对象。或者修改 async/sync 方法以返回已经详细说明的字符串列表/HtmlElements/whatever。
标签: c# winforms web-crawler task html-agility-pack