5.2. Introduciamo sgmllib.py

L'elaborazione dell'HTML è suddivisa in tre passi: spezzare l'HTML nei suoi elementi costitutivi, giocherellare con questi pezzi, infine ricostruire i pezzi nuovamente nell'HTML. Il primo passo è fatto da sgmllib.py, che è parte della libreria standard di Python

La chiave di lettura di questo capitolo sta nel capire che l'HTML non è solo testo, ma è testo strutturato. La struttura deriva da quella più o meno gerarchica dei tag di inizio e di fine. Solitamente non si lavora con l'HTML in questa maniera; ci si lavora per quel che riguarda il testo con un editor di testo, mentre, per quel che riguarda l'aspetto visuale, con un web browser o uno strumento per comporre pagine web. sgmllib.py mostra invece l'HTML dal punto di vista della sua struttura.

sgmllib.py contiene una classe importante: SGMLParser. SGMLParser suddivide l'HTML in parti utili, come tag di inizio e tag di fine. Non appena riesce a spezzare dei dati in parti utili, chiama un proprio metodo sulla base di ciò che ha trovato. Per poter usare questo parser, dovrete derivare la classe SGMLParser e sovrascrivere questi metodi. Questo è ciò che intendevo quando dissi che mostra l'HTML dal punto di vista della sua struttura: questa struttura determina la sequenza delle chiamate ai metodi e gli argomenti passati a ciascun metodo.

SGMLParser suddivide l'HTML in 8 tipi di dati e chiama un metodo separato per ognuno di loro:

Tag di inizio
Si tratta di un tag HTML che da inizio ad un blocco, come <html>, <head>, <body> o <pre> oppure di un tag solitario come <br> o <img>. Quando trova il nometag di inizio, SGMLParser cerca un metodo chiamato start_nometag oppure do_nometag. Per esempio, quando trova un tag <pre>, cercherà un metodo che si chiami start_pre oppure un do_pre. Se lo trova, SGMLParser chiama questo metodo passandogli una lista degli attributi del tag; altrimenti chiama il metodo unknown_starttag passandogli il nome del tag e la lista degli attributi.
Tag di fine
Si tratta di un tag HTML che chiude un blocco, come </html>, </head>, </body>, o </pre>. Quando trova un tag di fine, SGMLParser cerca un metodo chiamato end_nometag. Se lo trova, SGMLParser chiama questo metodo, altrimenti chiama unknown_endtag passandogli il nome del tag.
Riferimento a carattere
Un carattere di escape indicato dal suo equivalente decimale o esadecimale, come ad esempio &#160;. Quando viene trovato, SGMLParser chiama handle_charref passandogli il testo dell'equivalente carattere decimale o esadecimale.
Riferimento a entità
Una entità HTML, come &copy;. Quando viene trovata, SGMLParser chiama handle_entityref passandogli il nome dell'entità HTML.
Commento
Un commento HTML, racchiuso tra <!-- ... -->. Quando viene trovato, SGMLParser chiama handle_comment passandogli il corpo del commento.
Istruzioni di elaborazione
Un'istruzione di elaborazione HTML, racchiusa tra <? ... >. Quando viene trovata, SGMLParser chiama handle_pi passandogli il corpo dell'istruzione di elaborazione.
Dichiarazione
Una dichiarazione HTML, come ad esempio un DOCTYPE, racchiuso tra <! ... >. Quando viene trovata, SGMLParser chiama handle_decl passandogli il corpo della dichiarazione.
Testo
Un blocco di testo. Qualunque cosa che non si adatti a una della altre 7 categorie. Quando viene trovato, SGMLParser chiama handle_data passandogli il testo.
Importante
Python 2.0 ha un bug per il quale SGMLParser non riconosce del tutto le dichiarazioni (handle_decl non viene mai chiamato), questo implica che i DOCTYPE vengano ignorati senza che sia segnalato. Questo è stato corretto in Python 2.1.

sgmllib.py è fornito assieme ad una suite di test per chiarirne il funzionamento. Potete eseguire sgmllib.py passando il nome di un file HTML tramite la linea di comando, esso vi scriverà come risultato i tag e gli altri elementi che ha esaminato. Ciò viene fatto derivando la classe SGMLParser e definendo i metodi unknown_starttag, unknown_endtag, handle_data e gli altri metodi, di modo che, semplicemente, scrivano i loro argomenti.

Suggerimento
Nella IDE di Python su Windows, potete specificare argomenti da linea di comando nella finestra di dialogo “Run script”. Argomenti multipli vanno separati da spazi.

Esempio 5.4. Test di esempio di sgmllib.py

Questo è un frammento preso dall'indice della versione HTML di questo libro, toc.html.

<h1>
  <a name='c40a'></a>
  Dive Into Python
</h1>
<p class='pubdate'>
  28 Feb 2001
</p>
<p class='copyright'>
  Copyright copy 2000, 2001 by 
  <a href='mailto:[email protected]' title='send e-mail to the author'>
    Mark Pilgrim
  </a>
</p>
<p>
  <a name='c40ab2b4'></a>
  <b></b>
</p>
<p>
  This book lives at
  <a href='http://diveintopython.org/'>
    http://diveintopython.org/
  </a>
  .
  If you’re reading it somewhere else, you may not have the latest version.
</p>

Eseguendo questo frammento di codice, attraverso la suite di test di sgmllib.py, si ottiene il seguente risultato:

start tag: <h1>
start tag: <a name="c40a" >
end tag: </a>
data: 'Dive Into Python'
end tag: </h1>
start tag: <p class="pubdate" >
data: '28 Feb 2001'
end tag: </p>
start tag: <p class="copyright" >
data: 'Copyright '
*** unknown entity ref: &copy;
data: ' 2000, 2001 by '
start tag: <a href="mailto:[email protected]" title="send e-mail to the author" >
data: 'Mark Pilgrim'
end tag: </a>
end tag: </p>
start tag: <p>
start tag: <a name="c40ab2b4" >
end tag: </a>
start tag: <b>
end tag: </b>
end tag: </p>
start tag: <p>
data: 'This book lives at '
start tag: <a href="http://diveintopython.org/" >
data: 'http://diveintopython.org/'
end tag: </a>
data: ".\012If you’re reading it somewhere else, you may not have the lates"
data: 't version.\012'
end tag: </p>

Questo è ciò che troverete nel resto del capitolo: