In questa lezione ci concentreremo su una delle applicazioni più potenti di Puppeteer: il web scraping. Con Puppeteer possiamo estrarre dati da pagine web in modo automatizzato, evitando di dover copiare manualmente le informazioni. Questo approccio è utile per molteplici scopi, come il monitoraggio dei prezzi, la raccolta di dati per analisi di mercato o il recupero di contenuti da pagine web non facilmente accessibili tramite API ufficiali.
Esploreremo le basi del web scraping con Puppeteer, come selezionare e estrarre informazioni dai siti web e vedremo alcune best practice per evitare problemi comuni. Come blocchi da parte dei siti web.
Prima di procedere è fondamentale sottolineare che il web scraping potrebbe non essere legale in alcuni contesti. Alcuni siti web vietano esplicitamente lo scraping nei loro Termini di Servizio, e violarli potrebbe comportare conseguenze legali. Inoltre, estrarre dati sensibili o protetti da copyright senza autorizzazione può essere illegale. Tutto il contenuto di questa lezione è fornito a scopo puramente educativo. È responsabilità dell'utente verificare la legalità dello scraping prima di applicarlo a un sito web.
Cos'è il Web Scraping?
Il web scraping è una tecnica utilizzata per raccogliere informazioni da siti web attraverso l'uso di software automatizzati. Invece di visitare manualmente una pagina e copiare i dati, possiamo scrivere uno script che li estragga in modo automatico. Puppeteer è uno strumento ideale per il web scraping perché permette di:
- Caricare pagine come farebbe un vero utente.
- Interagire con gli elementi della pagina.
- Gestire JavaScript e contenuti dinamici.
- Simulare azioni dell'utente come clic e scrolling.
Una pagina di prova per operare con Puppeteer
Il file HTML può essere salvato e aperto localmente per testare gli script di web scraping con Puppeteer. Per testare la navigazione tra pagine, possiamo creare un altro file pagina2.html
con contenuti simili ma diversi titoli di articoli.
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>News Test Page</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
.article { margin-bottom: 10px; }
.pagination { margin-top: 20px; }
</style>
</head>
<body>
<h1>Ultime Notizie</h1>
<div class="articles">
<div class="article"><h2 class="titolo-articolo">Titolo Articolo 1</h2></div>
<div class="article"><h2 class="titolo-articolo">Titolo Articolo 2</h2></div>
<div class="article"><h2 class="titolo-articolo">Titolo Articolo 3</h2></div>
</div>
<div class="pagination">
<a href="pagina2.html" class="next-page">Pagina Successiva</a>
</div>
</body>
</html>
Estrazione di dati con Puppeteer
Ora vediamo come estrarre dati da una pagina web. Supponiamo di voler ottenere i titoli degli articoli di un sito di notizie.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://esempio.com/news');
const titoli = await page.evaluate(() => {
return Array.from(document.querySelectorAll('h2.titolo-articolo'))
.map(element => element.innerText);
});
console.log(titoli);
await browser.close();
})();
Nel dettaglio:
page.evaluate()
esegue codice JavaScript direttamente nel browser.document.querySelectorAll('h2.titolo-articolo')
seleziona tutti gli elementih2
con la classetitolo-articolo
.Array.from(...).map(...)
crea un array con i testi dei titoli.
Questo ci permette di ottenere un elenco con tutti i titoli degli articoli presenti sulla pagina.
Gestione dei contenuti dinamici con Puppeteer
Alcuni siti caricano i contenuti dinamicamente tramite JavaScript. Quindi potremmo dover aspettare che gli elementi appaiano prima di estrarre i dati. Possiamo farlo con waitForSelector()
:
await page.waitForSelector('h2.titolo-articolo');
Questo assicura che il nostro codice non tenti di leggere dati prima che siano disponibili.
Supponiamo di modificare la nostra pagina HTML con l'aggiunta di una funzione per caricare dinamicamente i titoli degli articoli tramite AJAX:
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>News Test Page</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
.article { margin-bottom: 10px; }
.pagination { margin-top: 20px; }
</style>
</head>
<body>
<h1>Ultime Notizie</h1>
<div class="articles">
<!-- Gli articoli saranno caricati dinamicamente qui -->
</div>
<div class="pagination">
<a href="pagina2.html" class="next-page">Pagina Successiva</a>
</div>
<script>
// Funzione per caricare dinamicamente i titoli degli articoli tramite AJAX
function caricaArticoli() {
// Dati di esempio per i titoli degli articoli
const articoli = [
{ "titolo": "Titolo Articolo 1" },
{ "titolo": "Titolo Articolo 2" },
{ "titolo": "Titolo Articolo 3" }
];
const container = document.querySelector('.articles');
articoli.forEach((articolo) => {
const div = document.createElement('div');
div.classList.add('article');
div.innerHTML = `<h2 class="titolo-articolo">${articolo.titolo}</h2>`;
container.appendChild(div);
});
}
// Carica gli articoli quando la pagina è caricata
window.onload = caricaArticoli;
</script>
</body>
</html>
Il codice per poter eseguire lo scraping di questa pagina è il seguente:
const puppeteer = require('puppeteer');
const fs = require('fs');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Naviga alla tua pagina HTML locale
await page.goto('http://localhost:3000'); // Assicurati di avere un server in esecuzione
// Aspetta che gli articoli siano caricati
await page.waitForSelector('.article');
// Estrai i titoli degli articoli
const titoli = await page.evaluate(() => {
return Array.from(document.querySelectorAll('.titolo-articolo'))
.map(element => element.innerText);
});
// Salva i dati in un file JSON
fs.writeFile('titoli_articoli.json', JSON.stringify(titoli, null, 2), (err) => {
if (err) {
console.error('Errore nel salvataggio dei dati', err);
} else {
console.log('Dati salvati in titoli_articoli.json');
}
});
await browser.close();
})();
Il codice innanzitutto, importa la libreria Puppeteer per interagire con il browser e la libreria fs
per la gestione dei file. All'interno di una funzione asincrona, viene avviato un browser e aperta una nuova pagina. La pagina locale viene caricata tramite un URL (assicurandosi che un server sia attivo sulla porta 3000
). Quindi il codice attende che un elemento con la classe .article
sia presente nella pagina, garantendo che gli articoli siano visibili prima di procedere.
Successivamente, il codice esegue un'operazione di scraping per estrarre i titoli degli articoli cercando tutti gli h2
con la classe .titolo-articolo
, raccogliendo il testo da ciascun elemento. I titoli estratti vengono poi salvati in un file JSON chiamato titoli_articoli.json
.
Se il salvataggio ha successo, viene stampato un messaggio di conferma. In caso di errore, viene restituito un messaggio d'errore. Infine, il browser viene chiuso per liberare risorse.
Navigazione tra pagine e paginazione con Puppeteer
Se vogliamo estrarre dati da più pagine (ad esempio, una serie di risultati paginati), possiamo automatizzare la navigazione:
let pagina = 1;
while (true) {
console.log(`Estrazione dati dalla pagina ${pagina}`);
const titoli = await page.evaluate(() => {
return Array.from(document.querySelectorAll('h2.titolo-articolo'))
.map(element => element.innerText);
});
console.log(titoli);
const nextButton = await page.$('a.next-page');
if (!nextButton) break;
await nextButton.click();
await page.waitForNavigation();
pagina++;
}
Qui:
- Controlliamo se esiste un pulsante "pagina successiva" (
a.next-page
). - Se esiste, clicchiamo su di esso e aspettiamo il caricamento della nuova pagina.
- Ripetiamo il processo fino a quando non ci sono più pagine da visitare.
Evitare blocchi da parte dei siti web con Puppeteer
Alcuni siti cercano di rilevare e bloccare l'attività di web scraping. Ecco alcune strategie per evitarlo:
Simulare un utente reale
Possiamo far sembrare che il nostro bot sia un vero utente impostando un User-Agent
personalizzato:
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64)');
Utilizzare il ritardo nei clic
Aggiungere un piccolo ritardo tra le azioni aiuta a evitare sospetti:
await page.click('button#submit', { delay: 100 });
Evitare il blocco con headless: false
Alcuni siti bloccano browser headless. Possiamo avviare Puppeteer in modalità visibile:
const browser = await puppeteer.launch({ headless: false });
Utilizzare un proxy
Se il sito blocca gli IP, possiamo utilizzare un proxy:
const browser = await puppeteer.launch({
args: ['--proxy-server=http://mio-proxy:8000']
});
Conclusioni: web scraping con Puppeteer
Abbiamo visto come usare Puppeteer per il web scraping, dall'estrazione di dati statici alla gestione di contenuti dinamici e navigazione tra pagine. Abbiamo anche discusso strategie per evitare blocchi e modi per salvare i dati estratti.
Tuttavia, è importante ribadire ancora una volta che il web scraping deve essere eseguito nel rispetto delle leggi e dei termini di servizio dei siti web coinvolti. Nella prossima lezione, esploreremo come generare screenshot e PDF di pagine web in modo avanzato.