5.3. Estrarre informazioni da documenti HTML

Per estrarre informazioni da documenti HTML, create una sottoclasse SGMLParser e definite metodi per ogni tag o altro che volete catturare.

Il primo passo per estrarre informazioni da un documento HTML è prendere del codice HTML. Se avete del codice HTML in giro per il vostro hard disk, potete usare delle funzioni per leggerlo, ma il vero divertimento inizia quando prendete l'HTML direttamente da pagine web.

Esempio 5.5. Introdurre urllib

>>> import urllib                                       1
>>> sock = urllib.urlopen("http://diveintopython.org/") 2
>>> htmlSource = sock.read()                            3
>>> sock.close()                                        4
>>> print htmlSource                                    5
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head>
      <meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1'>
   <title>Dive Into Python</title>
<link rel='stylesheet' href='diveintopython.css' type='text/css'>
<link rev='made' href='mailto:[email protected]'>
<meta name='keywords' content='Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free'>
<meta name='description' content='a free Python tutorial for experienced programmers'>
</head>
<body bgcolor='white' text='black' link='#0000FF' vlink='#840084' alink='#0000FF'>
<table cellpadding='0' cellspacing='0' border='0' width='100%'>
<tr><td class='header' width='1%' valign='top'>diveintopython.org</td>
<td width='99%' align='right'><hr size='1' noshade></td></tr>
<tr><td class='tagline' colspan='2'>Python&nbsp;for&nbsp;experienced&nbsp;programmers</td></tr>

[...snip...]
1 Il modulo urllib è parte della libreria standard di Python. Contiene delle funzioni che consentono di ottenere e scaricare informazioni da URL internet (fondamentalmente pagine web).
2 Il modo più semplice di utilizzare le urllib è scaricare l'intero testo di una pagina web con la funzione urlopen. Aprire una URL è simile ad aprire un file. Il valore di ritorno di urlopen somiglia ad un oggetto file, in quanto ha alcuni metodi propri degli oggetti file.
3 La cosa più semplice da fare con l'oggetto ritornato da urlopen è read, che legge tutto il codice HTML della pagina web in una sola stringa. L'oggetto supporta anche readlines, che legge il testo riga per riga inserendolo in una lista.
4 Quando avete finito di utilizzare l'oggetto, assicuratevi di chiuderlo (close), proprio come un normale oggetto file.
5 Adesso abbiamo tutto il codice HTML della pagina web di http://diveintopython.org/ in una stringa, e siamo pronti ad analizzarlo.

Esempio 5.6. Introdurre urllister.py

Se non lo avete ancora fatto, potete scaricare questo ed altri esempi usati in questo libro.


from sgmllib import SGMLParser

class URLLister(SGMLParser):
    def reset(self):                              1
        SGMLParser.reset(self)
        self.urls = []

    def start_a(self, attrs):                     2
        href = [v for k, v in attrs if k=='href'] 3 4
        if href:
            self.urls.extend(href)
1 reset è chiamata dal metodo __init__ di SGMLParser, e può essere anche chiamata manualmente non appena è stata creata un'istanza dell'analizzatore. Quindi, se avete bisogno di fare una qualsiasi inizializzazione, fatela in reset, non in __init__, così che sarà adeguatamente reinizializzata quando qualcuno riutilizza un'istanza dell'analizzatore.
2 start_a è chiamata da SGMLParser ogni qual volta trova il tag <a>. Il tag può contenere un attributo href, e/o altri attributi, come name o title. Il parametro attrs è una lista di tuple, [(attributo, valore), (attributo, valore), ...]. Nel caso in cui ci fosse solo <a>, un valido (ma inutile) tag HTML, attrs sarebbe una lista vuota.
3 Possiamo controllare se questo tag <a> ha un attributo href tramite una semplice list comprehension di valori multipli.
4 Confronti tra stringhe quale k=='href' sono sempre case-sensitive, ma in questo caso non c'è problema, in quanto SGMLParser converte i nomi degli attributi in caratteri minuscoli durante la costruzione di attrs.

Esempio 5.7. Utilizzare urllister.py

>>> import urllib, urllister
>>> usock = urllib.urlopen("http://diveintopython.org/")
>>> parser = urllister.URLLister()
>>> parser.feed(usock.read())         1
>>> usock.close()                     2
>>> parser.close()                    3
>>> for url in parser.urls: print url 4
toc.html
#download
toc.html
history.html
download/dip_pdf.zip
download/dip_pdf.tgz
download/dip_pdf.hqx
download/diveintopython.pdf
download/diveintopython.zip
download/diveintopython.tgz
download/diveintopython.hqx

[...snip...]
1 Chiama il metodo feed, definito in SGMLParser, per raggiungere il codice HTML in parser. [7] Prende una stringa, che è ciò che usock.read() ritorna.
2 Come per i file, potete chiudere i vostri oggetti URL non appena avete finito di utilizzarli.
3 Dovreste anche chiudere il vostro oggetto parser, ma per una ragione diversa. Non è sicuro che il metodo feed processi tutto il codice HTML che gli viene passato; potrebbe bufferizzarlo, aspettandone altro. Una volta che non ce n'è più, chiamate close per svuotare il buffer e forzare l'analisi di ogni cosa.
4 Una volta che parser è chiuso, l'analisi è completa e parser.urls conterrà l'elenco di tutti i nostri collegamenti alle URL presenti nel nostro documento HTML.

Footnotes

[7] Il termine tecnico per un analizzatore come SGMLParser è consumatore: questa classe consuma codice HTML e lo decompone. Presumibilmente, il nome feed (nutrire, ndt) è stato scelto proprio per adattarsi all'analogia del “consumatore”. Personalmente, la cosa mi fa pensare ad un esemplare in uno zoo, in una gabbia scura in cui non si vedano piante o vita di alcun tipo, ma in cui, se restate immobili e guardate molto da vicino, potete scorgere due occhi piccoli e lucenti che vi osservano di rimando dall'angolo più lontano, per convincervi subito dopo che è solo uno scherzo della vostra immaginazione L'unico modo per capire che non si tratta semplicemente di una gabbia vuota è un piccolo cartello sulle sbarre, dall'aspetto innocuo, che dice “Non date da mangiare al parser”. Ma forse sono solo io. Ad ogni modo, è un'interessante quadretto mentale.