¿Cómo descargar todas las imágenes de un sitio en C # + HtmlAgilityPack?

.net c# html-agility-pack parsing

Pregunta

Uso programas como: Teleport, HTTrack, Offline Explorer, DownThemAll y otros. Todas las imágenes se encuentran solo - DownThemAll. Pero tengo muchas páginas, con las que desea descargar imágenes de los productos. DownThemAll no es adecuado.

Escribí el programa en C # + HtmlAgilityPack, pero ella no encontró todas las fotos de los productos.

Idealmente, me gustaría lo siguiente:

  1. El programa carga el archivo URLS.txt. En que tales referencias son:

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

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

etc

  1. El programa carga en estas páginas todas las imágenes de los productos.

¿Qué recomiendas? Tal vez me equivoque al escribir el código en 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);
                }
            }

Respuesta aceptada

Te estabas yendo bien. En esta solución estoy usando LINQ y TPL.

Este sitio utiliza la paginación, por lo que debe cargar todas las páginas para poder descargar todas las imágenes del producto.

  1. Cargar primera página (HtmlNode)
  2. Descubre cuántas páginas tiene este catálogo de productos.
  3. Cargar otras páginas (HtmlNode)

Entonces tienes una colección de páginas.

  1. Carga los nodos img que quieras descargar.
  2. Cree una tupla con la URL de imagen y la nueva instancia de WebClient
  3. Descargar imagen
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;
    }
}

Y puedes usar así:

DownloadImagesFromUrl("http://www.onlinetrade.ru/catalogue/televizori-c181/", @"C:\temp\televizori-c181\images");

Y luego se descargaron 178 imágenes.

Cuando las imágenes se están descargando, a veces puede fallar, por lo que te sugiero que implementes el patrón Reintentar usando Polly .

Obs . : El cliente web no admite operaciones en paralelo, por lo que creo uno para cada url de imagen.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué