Come scaricare tutte le immagini da un sito in C # + HtmlAgilityPack?

.net c# html-agility-pack parsing

Domanda

Uso programmi come: Teletrasporto, HTTrack, Offline Explorer, DownThemAll e altri. Tutte le immagini si trovano solo - DownThemAll. Ma ho un sacco di pagine, con le quali vuoi scaricare le foto dei prodotti. DownThemAll non è adatto.

Ho scritto il programma su C # + HtmlAgilityPack, ma non ha trovato tutte le foto dei prodotti.

Idealmente, mi piacerebbe il seguente:

  1. Il programma carica il file URLS.txt. In cui tali riferimenti sono:

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

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

eccetera

  1. Il programma carica su queste pagine tutte le foto dei prodotti.

Che cosa consigli? Forse ho sbagliato a scrivere il codice su 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);
                }
            }

Risposta accettata

Stavi andando bene. In questa soluzione sto usando LINQ e TPL.

Questo sito utilizza l'impaginazione, quindi è necessario caricare tutte le pagine per poter scaricare tutte le immagini del prodotto.

  1. Carica la prima pagina (HtmlNode)
  2. Scopri quante pagine ha questo catalogo prodotti
  3. Carica altre pagine (HtmlNode)

Allora hai una collezione di pagine

  1. Carica i nodi img che vuoi scaricare
  2. Crea una tupla con l'url de Image e la nuova istanza WebClient¹
  3. Scarica l'immagine
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;
    }
}

E puoi usare così:

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

E poi 178 immagini sono state scaricate.

Quando le immagini vengono scaricate, a volte può fallire, quindi ti suggerisco di implementare il pattern Riprova usando Polly .

Obs¹ : WebClient non supporta l'operazione parallela, quindi ne creo uno per ciascun URL immagine.



Related

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché