我正在尝试通过创建一个简单的刮刀来学习.NET技术和C#,它应该从维基百科中检索一些地理数据。
首先,我创建了这个方法,从this维基百科网站返回表格中所有国家/地区的所有链接:
public IEnumerable<string> GetLinkToAllCountries()
{
return from node in XElement.Load(_URL.AbsoluteUri).Elements("body").Descendants()
where node.Name.LocalName == "a"
&& node.Parent.Name.LocalName == "td"
&& node.Parent.Parent.Name.LocalName == "tr"
&& node.Attribute("href") != null
&& node.Attribute("title") != null
select _URL.Scheme + "//" + _URL.Host + node.Attribute("href").Value;
}
这很好用并返回每个国家Wiki页面的链接列表。其次,我想访问每个国家的页面并检索首都。
我写了类似的东西,但我无法让它起作用:
public IEnumerable<string> ListOfCapitals() {
var links = GetLinkToAllCountries();
return from link in links
from node in XElement.Load(link).Elements("body").Descendants()
where node.Name.LocalName == "a"
&& node.Parent.Name == "td"
&& node.Attribute("title") != null
select node.Attribute("title").Value;
}
它没有列出大写字母,Visual Studio似乎制作了一些指向System.Threading的程序集指针。我是否应该因为工作负荷而写异步(访问~200个网站并从每个网站检索数据)?如果没有违反任何规则,我也会喜欢这种方法的一般反馈。谢谢!
答案 0 :(得分:0)
我认为最好的方法是通过TPL:
https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl
重构 - 给定以下类:
public class WebScrapper
{
public IEnumerable<string> GetLinkToAllCountries(Uri uri)
{
return from node in XElement.Load(uri.AbsoluteUri).Elements("body").Descendants()
where node.Name.LocalName == "a"
&& node.Parent.Name.LocalName == "td"
&& node.Parent.Parent.Name.LocalName == "tr"
&& node.Attribute("href") != null
&& node.Attribute("title") != null
select uri.Scheme + "://" + uri.Host + node.Attribute("href").Value;
}
public IEnumerable<string> ListOfCapitals(string link)
{
return from node in XElement.Load(link).Elements("body").Descendants()
where node.Name.LocalName == "a"
&& node.Parent.Name == "td"
&& node.Attribute("title") != null
select node.Attribute("title").Value;
}
}
然后您可以使用以下内容:
var webScrapper = new WebScrapper();
var countryLinks =
webScrapper.GetLinkToAllCountries(
new Uri("https://en.wikipedia.org/wiki/List_of_countries_and_dependencies_by_population"));
var capitals = countryLinks
.AsParallel()
.WithDegreeOfParallelism(Convert.ToInt32(Math.Ceiling(Environment.ProcessorCount * 0.75)))
.SelectMany(s => webScrapper.ListOfCapitals(s))
.ToList();
WithDegreeOfParallelism
- 将用于处理查询的并发执行任务的数量。
还需要考虑的是XElement.Load(uri.AbsoluteUri)
中的GetLinkToAllCountries
和XElement.Load(link)
中ListOfCapitals
的依赖关系。我重构了这个以便有一层抽象 - 这样linq查询可以用模拟进行单元测试。