如何从 C# + HtmlAgilityPack 上的站点下载所有图像?
How to download all images from a site on the C# + HtmlAgilityPack?
我使用的程序有:Teleport、HTTrack、Offline Explorer、DownThemAll 等。所有图片只能找到 - DownThemAll。但是我有很多页面,你要用它来下载商品的图片。 DownThemAll 不适合。
我是用C#+HtmlAgilityPack写程序的,但是她没有找到所有的商品图片
理想情况下,我想要以下内容:
- 程序加载文件URLS.txt。其中此类引用是:
http://www.onlinetrade.ru/catalogue/televizori-c181/
http://www.onlinetrade.ru/catalogue/3d_ochki-c130/
etc
- 程序会在这些页面上加载所有商品图片。
你有什么建议?也许我在 C# 上编写代码是错误的?
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
WebClient wc = new WebClient();
string url = wc.DownloadString("http://www.onlinetrade.ru/catalogue/televizori-c181/");
doc.LoadHtml(url);
HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//a[@class='catalog__displayedItem__columnFotomainLnk']/img");
if (nodes != null)
{
foreach (HtmlNode node in nodes)
{
listBox1.Items.Add(node.Attributes["src"].Value);
}
}
你进展顺利。在此解决方案中,我使用的是 LINQ 和 TPL。
本网站使用分页,因此您必须加载所有页面才能下载所有产品图片。
- 加载第一页 (HtmlNode)
- 查看此产品目录有多少页
- 加载其他页面(HtmlNode)
然后你有一个页面集合
- 加载您要下载的 img 节点
- 使用图像 url 和新的 WebClient 实例创建一个元组¹
- 下载图片
public class ImageDownloader
{
public void DownloadImagesFromUrl(string url, string folderImagesPath)
{
var uri = new Uri(url + "/?per_page=50");
var pages = new List<HtmlNode> { LoadHtmlDocument(uri) };
pages.AddRange(LoadOtherPages(pages[0], url));
pages.SelectMany(p => p.SelectNodes("//a[@class='catalog__displayedItem__columnFotomainLnk']/img"))
.Select(node => Tuple.Create(new UriBuilder(uri.Scheme, uri.Host, uri.Port, node.Attributes["src"].Value).Uri, new WebClient()))
.AsParallel()
.ForAll(t => DownloadImage(folderImagesPath, t.Item1, t.Item2));
}
private static void DownloadImage(string folderImagesPath, Uri url, WebClient webClient)
{
try
{
webClient.DownloadFile(url, Path.Combine(folderImagesPath, Path.GetFileName(url.ToString())));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static IEnumerable<HtmlNode> LoadOtherPages(HtmlNode firstPage, string url)
{
return Enumerable.Range(1, DiscoverTotalPages(firstPage))
.AsParallel()
.Select(i => LoadHtmlDocument(new Uri(url + "/?per_page=50&page=" + i)));
}
private static int DiscoverTotalPages(HtmlNode documentNode)
{
var totalItemsDescription = documentNode.SelectNodes("//div[@class='catalogItemList__numsInWiev']").First().InnerText.Trim();
var totalItems = int.Parse(Regex.Match(totalItemsDescription, @"\d+$").ToString());
var totalPages = (int)Math.Ceiling(totalItems / 50d);
return totalPages;
}
private static HtmlNode LoadHtmlDocument(Uri uri)
{
var doc = new HtmlDocument();
var wc = new WebClient();
doc.LoadHtml(wc.DownloadString(uri));
var documentNode = doc.DocumentNode;
return documentNode;
}
}
你可以这样使用:
DownloadImagesFromUrl("http://www.onlinetrade.ru/catalogue/televizori-c181/", @"C:\temp\televizori-c181\images");
然后下载了178张图片。
下载图片的时候,有时会失败,所以我建议你实施Retry pattern using Polly。
Obs¹: WebClient 不支持并行操作,所以我为每个图像创建一个 url。
我使用的程序有:Teleport、HTTrack、Offline Explorer、DownThemAll 等。所有图片只能找到 - DownThemAll。但是我有很多页面,你要用它来下载商品的图片。 DownThemAll 不适合。
我是用C#+HtmlAgilityPack写程序的,但是她没有找到所有的商品图片
理想情况下,我想要以下内容:
- 程序加载文件URLS.txt。其中此类引用是:
http://www.onlinetrade.ru/catalogue/televizori-c181/
http://www.onlinetrade.ru/catalogue/3d_ochki-c130/
etc
- 程序会在这些页面上加载所有商品图片。
你有什么建议?也许我在 C# 上编写代码是错误的?
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
WebClient wc = new WebClient();
string url = wc.DownloadString("http://www.onlinetrade.ru/catalogue/televizori-c181/");
doc.LoadHtml(url);
HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//a[@class='catalog__displayedItem__columnFotomainLnk']/img");
if (nodes != null)
{
foreach (HtmlNode node in nodes)
{
listBox1.Items.Add(node.Attributes["src"].Value);
}
}
你进展顺利。在此解决方案中,我使用的是 LINQ 和 TPL。
本网站使用分页,因此您必须加载所有页面才能下载所有产品图片。
- 加载第一页 (HtmlNode)
- 查看此产品目录有多少页
- 加载其他页面(HtmlNode)
然后你有一个页面集合
- 加载您要下载的 img 节点
- 使用图像 url 和新的 WebClient 实例创建一个元组¹
- 下载图片
public class ImageDownloader
{
public void DownloadImagesFromUrl(string url, string folderImagesPath)
{
var uri = new Uri(url + "/?per_page=50");
var pages = new List<HtmlNode> { LoadHtmlDocument(uri) };
pages.AddRange(LoadOtherPages(pages[0], url));
pages.SelectMany(p => p.SelectNodes("//a[@class='catalog__displayedItem__columnFotomainLnk']/img"))
.Select(node => Tuple.Create(new UriBuilder(uri.Scheme, uri.Host, uri.Port, node.Attributes["src"].Value).Uri, new WebClient()))
.AsParallel()
.ForAll(t => DownloadImage(folderImagesPath, t.Item1, t.Item2));
}
private static void DownloadImage(string folderImagesPath, Uri url, WebClient webClient)
{
try
{
webClient.DownloadFile(url, Path.Combine(folderImagesPath, Path.GetFileName(url.ToString())));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static IEnumerable<HtmlNode> LoadOtherPages(HtmlNode firstPage, string url)
{
return Enumerable.Range(1, DiscoverTotalPages(firstPage))
.AsParallel()
.Select(i => LoadHtmlDocument(new Uri(url + "/?per_page=50&page=" + i)));
}
private static int DiscoverTotalPages(HtmlNode documentNode)
{
var totalItemsDescription = documentNode.SelectNodes("//div[@class='catalogItemList__numsInWiev']").First().InnerText.Trim();
var totalItems = int.Parse(Regex.Match(totalItemsDescription, @"\d+$").ToString());
var totalPages = (int)Math.Ceiling(totalItems / 50d);
return totalPages;
}
private static HtmlNode LoadHtmlDocument(Uri uri)
{
var doc = new HtmlDocument();
var wc = new WebClient();
doc.LoadHtml(wc.DownloadString(uri));
var documentNode = doc.DocumentNode;
return documentNode;
}
}
你可以这样使用:
DownloadImagesFromUrl("http://www.onlinetrade.ru/catalogue/televizori-c181/", @"C:\temp\televizori-c181\images");
然后下载了178张图片。
下载图片的时候,有时会失败,所以我建议你实施Retry pattern using Polly。
Obs¹: WebClient 不支持并行操作,所以我为每个图像创建一个 url。