如何从C#+ HtmlAgilityPack上的网站下载所有图像?

时间:2015-12-25 14:13:32

标签: c# .net parsing html-agility-pack

我使用的程序包括:Teleport,HTTrack,Offline Explorer,DownThemAll等。所有图片仅供参考 - DownThemAll。但我有很多页面,你想用它们下载商品的图片。 DownThemAll不合适。

我在C#+ HtmlAgilityPack上编写了这个程序,但她没有找到所有商品的图片。

理想情况下,我想要以下内容:

  1. 程序加载文件URLS.txt。其中提到的是:
  2.   

    http://www.onlinetrade.ru/catalogue/televizori-c181/

         

    http://www.onlinetrade.ru/catalogue/3d_ochki-c130/

         

    1. 程序会在这些页面上加载商品的所有图片。
    2. 你有什么建议?也许我在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);
                      }
                  }
      

1 个答案:

答案 0 :(得分:1)

你进展顺利。在这个解决方案中,我使用的是LINQ和TPL。

此网站使用分页,因此您必须加载所有网页才能下载所有产品的图片。

  1. 加载第一页(HtmlNode)
  2. 了解此产品目录中有多少页
  3. 加载其他页面(HtmlNode)
  4. 然后你有一个页面集合

    1. 加载要下载的img节点
    2. 使用de Image网址和新的WebClient实例¹
    3. 创建一个元组
    4. 下载图片
    5. 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实施Polly

      Obs¹:WebClient不支持并行操作,因此我为每个图片网址创建一个。