Salta al contenuto

Come ignorare gli URL non HTML durante la scansione Web utilizzando C#

Introduzione

La scansione web è il processo di visita programmatica delle pagine web e di estrazione del loro contenuto e dei collegamenti in uscita per eseguire la scansione ricorsiva di un sito web. Quando si crea un web crawler, è importante recuperare e analizzare solo le pagine Web HTML reali ignorando altri tipi di file come immagini, video, PDF, ecc. Questo articolo spiegherà due metodi efficaci per filtrare gli URL non HTML in un Web C# cingolato:

  1. Controllo del suffisso URL rispetto a un elenco di estensioni di file indesiderate
  2. Esecuzione di una richiesta HEAD leggera e ispezione dell'intestazione della risposta Content-Type

Implementando queste tecniche, puoi aumentare l'efficienza del tuo crawler ed evitare richieste ed elaborazioni non necessarie. Immergiamoci nei dettagli di ciascun metodo e vediamo come applicarli nella pratica.

Metodo 1: controlla i suffissi URL per le estensioni di file indesiderate

Un modo semplice per ignorare gli URL non HTML è guardare l'estensione del file alla fine della stringa dell'URL. Puoi mantenere un elenco di estensioni comuni utilizzate per immagini, file multimediali, documenti e altre risorse non relative alle pagine Web. Quindi, prima di recuperare un URL, estrai il suo suffisso e saltalo se corrisponde a una di quelle estensioni.

Ecco uno snippet di codice che mostra come filtrare gli URL utilizzando questo approccio in C#:

HashSet<string> UnwantedExtensions = new HashSet<string> { 
  "jpg", "jpeg", "png", "gif", "bmp", "tiff",  // Images
  "mp4", "avi", "mov", "wmv", "flv", "webm",   // Videos 
  "mp3", "wav", "aac", "flac", "ogg",          // Audio
  "pdf", "doc", "docx", "xls", "xlsx", "ppt",  // Documents
  "zip", "tar", "gz", "rar", "7z"              // Archives
}; 

Uri uri = new Uri("http://example.com/image.jpg");
string extension = Path.GetExtension(uri.AbsolutePath).ToLower().TrimStart(‘.‘);

if (UnwantedExtensions.Contains(extension))
{
   Console.WriteLine($"Skipping URL with extension ‘{extension}‘: {uri}");
}
else 
{
   Console.WriteLine($"Fetching URL: {uri}");
   // Crawl the HTML page...
}

Questo codice definisce a HashSet di estensioni di file indesiderate, quindi per un determinato URL estrae l'estensione utilizzando Path.GetExtension(). Se l'estensione minuscola e punteggiata esiste nel file UnwantedExtensions impostato, l'URL viene saltato. Altrimenti, verrà recuperato e sottoposto a scansione come pagina HTML.

Il grande vantaggio di questo metodo è che è molto veloce: basta una semplice operazione su una stringa per URL. Lo svantaggio è che si basa su URL con l'estensione di file corretta, il che potrebbe non essere sempre il caso. È anche possibile avere pagine HTML con .asp or .php estensioni che vorremmo scansionare ma che potrebbero essere filtrate.

Metodo 2: eseguire una richiesta HEAD e ispezionare l'intestazione del tipo di contenuto

Un approccio più efficace, ma leggermente più lento, consiste nell'eseguire una richiesta HEAD leggera per ciascun URL e controllare l'intestazione Content-Type nella risposta. Una richiesta HEAD è proprio come una richiesta GET, tranne che chiede al server di restituire solo le intestazioni della risposta e non il contenuto effettivo.

L'intestazione Content-Type indica il tipo di supporto della risorsa richiesta. Per le pagine HTML, il tipo di contenuto sarà in genere "testo/html". Controllando questo valore di intestazione, puoi determinare in modo più affidabile se un URL punta a una pagina HTML o a qualche altro tipo di file.

Ecco come implementarlo in C#:

HttpClient httpClient = new HttpClient();

Uri uri = new Uri("http://example.com/page");
HttpRequestMessage headRequest = new HttpRequestMessage(HttpMethod.Head, uri);
HttpResponseMessage response = await httpClient.SendAsync(headRequest);

string contentType = response.Content.Headers.ContentType?.MediaType;

if (contentType == "text/html")
{
   Console.WriteLine($"Fetching HTML page: {uri}");
   // Crawl the HTML page...
}  
else
{
   Console.WriteLine($"Skipping non-HTML URL with Content-Type ‘{contentType}‘: {uri}");
}

Questo invia una richiesta HEAD asincrona utilizzando HttpClient e recupera l'intestazione Content-Type dalla risposta. Se il tipo di supporto è "testo/html", l'URL viene recuperato e analizzato come una pagina HTML. Altrimenti viene saltato e viene registrato il tipo di contenuto non HTML.

Il vantaggio delle richieste HEAD è che ti danno una risposta più definitiva sul tipo di contenuto direttamente dal server. Il potenziale svantaggio è la latenza aggiuntiva del viaggio di andata e ritorno al server, che può sommarsi per un gran numero di URL. Tuttavia, le richieste HEAD sono in genere piuttosto veloci poiché non viene restituito alcun contenuto.

Combinare i due metodi per la massima efficacia

Per la migliore copertura ed efficienza, ti consiglio di utilizzare entrambi i metodi sopra indicati insieme nel tuo web crawler C#. Controllando innanzitutto l'estensione URL rispetto a una lista nera, puoi filtrare rapidamente gli URL non HTML evidenti senza alcuna richiesta. Quindi, per gli URL che superano tale controllo, puoi eseguire una richiesta HEAD per verificare che si tratti effettivamente di una pagina HTML prima di recuperarla completamente.

Ecco come potrebbe apparire la logica di scansione principale mettendo tutto insieme:

public async Task Crawl(Uri uri) 
{
  string extension = Path.GetExtension(uri.AbsolutePath).ToLower().TrimStart(‘.‘);

  if (UnwantedExtensions.Contains(extension))
  {
    Console.WriteLine($"Skipping URL with unwanted extension ‘{extension}‘: {uri}");
    return;
  }

  if (VisitedUrls.Contains(uri))
  {
    Console.WriteLine($"Skipping already visited URL: {uri}");
    return;
  }

  HttpRequestMessage headRequest = new HttpRequestMessage(HttpMethod.Head, uri);
  HttpResponseMessage headResponse = await _httpClient.SendAsync(headRequest);

  string contentType = headResponse.Content.Headers.ContentType?.MediaType;

  if (contentType != "text/html")
  {    
    Console.WriteLine($"Skipping non-HTML URL with Content-Type ‘{contentType}‘: {uri}");
    return;
  }

  VisitedUrls.Add(uri);

  HttpResponseMessage getResponse = await _httpClient.GetAsync(uri);
  string content = await getResponse.Content.ReadAsStringAsync();

  Console.WriteLine($"Crawled URL: {uri}");

  // Parse links from HTML and queue them for crawling
  CrawlQueue.Enqueue(ExtractLinks(uri, content));
}

La sezione Crawl Il metodo controlla innanzitutto l'estensione del file dell'URL e la salta se si trova nell'hashset delle estensioni indesiderate. Quindi controlla se l'URL è già stato visitato e, in tal caso, lo salta. Successivamente esegue una richiesta HEAD e verifica che il tipo di contenuto sia HTML prima di aggiungere l'URL al file VisitedUrls hashset, recuperando completamente il contenuto e analizzando i collegamenti da mettere in coda per un'ulteriore scansione.

Utilizzati insieme in questo modo, il filtro delle estensioni e le richieste HEAD forniscono un efficace uno-due per ignorare il contenuto non HTML durante la scansione. Il controllo dell'estensione è un veloce filtro preliminare, mentre la richiesta HEAD è la conferma finale prima di impegnarsi nel recupero dell'intera pagina.

Altre considerazioni e migliori pratiche

Oltre a filtrare gli URL non HTML, ci sono alcune altre cose importanti da tenere a mente quando si crea un web crawler ben funzionante ed efficiente:

  • Rispetta sempre le regole del file robots.txt e non eseguire la scansione delle pagine non consentite. Puoi analizzare i file robots.txt e confrontarli con gli URL prima della scansione.

  • Limita la velocità di scansione e il numero di richieste simultanee per evitare di sovraccaricare i server. Una buona linea guida è non più di una richiesta al secondo per dominio.

  • Gestisci con garbo i codici di stato HTTP, i timeout e gli errori. Riprova gli errori con backoff esponenziale e scopri quando arrenderti.

  • Tieni traccia degli URL già visitati utilizzando un hashset, un database o una struttura dati efficiente per evitare di ripetere la scansione dei contenuti duplicati. Un filtro Bloom è una buona opzione salvaspazio.

Seguendo queste pratiche e implementando il filtro solo HTML, sarai sulla buona strada per creare un web crawler educato e mirato utilizzando C#. Le tecniche spiegate in questo articolo dovrebbero darti tutto ciò di cui hai bisogno per evitare contenuti irrilevanti e concentrarti sulle pagine HTML che ti interessano.

Conclusione

I web crawler sono uno strumento potente per esplorare e analizzare i contenuti dei siti web, ma per essere efficienti ed educati è fondamentale che si concentrino sulle pagine HTML effettive e saltino altri tipi di URL. In questo articolo abbiamo imparato due tecniche complementari per eseguire questa operazione in un crawler C#:

  1. Filtrare le estensioni URL indesiderate
  2. Controllo dell'intestazione Content-Type con una richiesta HEAD

Abbiamo spiegato come implementare entrambi i metodi e poi abbiamo visto come combinarli per ottenere una copertura più completa. Abbiamo anche accennato ad alcune altre best practice dei crawler, come il rispetto del file robots.txt e la limitazione del tasso di richieste.

Ci auguriamo che ora tu abbia una solida conoscenza di come ignorare in modo efficiente gli URL non HTML nei tuoi web crawler. L'applicazione di queste tecniche ti aiuterà a mantenere il tuo crawler veloce e concentrato evitando carichi inutili sui server.

Ecco alcune risorse aggiuntive che potresti voler consultare per saperne di più:

Buona scansione (selettiva)!

Partecipa alla conversazione

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati con *