segunda-feira, 9 de abril de 2007

Beautiful Soup e HTML Scrapping em Python

Fazer o parsing de uma página HTML que está corretamente formatada como XHTML em Python é fácil: podemos usar o módulo minidom ou, dependendo da situação, o (c)ElementTree.

Mas, e se a página não está tão corretamente formatada assim? Aí entra em cena um módulo muito interessante: o Beautiful Soup. Segundo a definição no site:O Beautiful Soup é um parser de HTML/XML para Python que pode transformar até mesmo marcação inválida em uma árvore analítica. Ele provê um modo idiomático de navegar, procurar e modificar a árvore de elementos. Ele normalmente salva o programador de horas ou dias de trabalho. Existe também um porte para Ruby chamado Rubyful Soup. (Embora o parser de HTML mal-formatado mais conhecido em Ruby seja o Hipcrot).

Um pequeno exemplo prático: vamos obter a lista das 20 linguagens de programação listadas no tiobe. Se você observar, verá que quase todo o documento está dentro de uma tabela, mesmo que isso não faça muito sentido.

Tentar fazer o parsing dessa HTML com o minidom gera uma bela exceção:

>>> dom3 = parseString(html)
Traceback (most recent call last):
File "", line 1, in ?
File "/usr/lib/python2.4/site-packages/_xmlplus/dom/minidom.py", line 1925, in parseString
return expatbuilder.parseString(string)
File "/usr/lib/python2.4/site-packages/_xmlplus/dom/expatbuilder.py", line 942, in parseString
return builder.parseString(string)
File "/usr/lib/python2.4/site-packages/_xmlplus/dom/expatbuilder.py", line 223, in parseString
parser.Parse(string, True)
xml.parsers.expat.ExpatError: mismatched tag: line 11, column 2


Ao invés disso, vamos usar o Beautiful Soup:


import urllib2
from BeautifulSoup import BeautifulSoup

tiobe = urllib2.urlopen('http://www.tiobe.com/tiobe_index/index.htm')

soup = BeautifulSoup(tiobe.read())
table = soup.findAll(id='Table2') #encontramos a tabela com o id 'Table2'
trs = soup.findAll('tr')
for tr in trs: #navegando pelos trs
tds = tr.findAll('td')
# Por causa da bagunça da página do tiobe, é necessário verificar se existem 7 dentro do tr. São esses que nos interessam.
if len(tds) == 7:
link = tds[3].find('a')
print(link.contents[0])


Em época em que se fala muito de web semântica, muitos sites oferecem conteúdo de forma razoavelmente mal formatada.Nesse mar de informação não semântica, o Beautiful Soup pode ser uma boa saída pra obter informações desses sites!
blog comments powered by Disqus