crawler com beautiful soup
Publicado; junho 12, 2008 Filed under: programação, python, rede | Tags: beautiful soup, brasileiro, campeonato, crawler, html, palmeiras, parser, python 1 Comment »Hoje precisei escrever uns programas pra extrair cotação de moedas do Banco Central. Aí, pra facilitar escrevi uma classe bem abstrata que faz o trabalho básico de ir até o website e fazer o GET ou POST, e retornar o conteúdo.
Veja que beleza:
# coding: utf-8
# 2008-06-11 AF
# crawler.py
import urllib, httplib
class crawler:
data = ''
host = None
method = 'GET'
params = {}
headers = {}
request = '/'
def __call__(self, fetch_anyway=False):
if not self.host:
raise ValueError('You must provide at least the host')
if not self.data:
# make the connection
fd = httplib.HTTPConnection(self.host)
# set the params and send the request
params = urllib.urlencode(self.params)
fd.request(self.method, self.request, params, self.headers)
# get the response
response = fd.getresponse()
self.status, self.reason = response.status, response.reason
# read the data
if self.status == 200 or fetch_anyway is True:
self.data = response.read()
fd.close()
return self.dataBasicamente, se eu criar uma classe que herda dela e especificar apenas o host ela, já funciona. Depois de todo o trabalho, resolvi fazer um programa relativamente simples que extrai o desempenho dos clubes do Campeonato Brasileiro 2008, usando o site da Gazeta Esportiva.
Pra interpretar o conteúdo de maneira bem fácil e rápida, usei o Beautiful Soup. Apesar do meu Palmeiras não estar bem, com esse papo furado ai do Luxa, é legal ver a lista de desempenhos – especialmente por não ter o Corinthians nela, ainda mais depois da derrota de hoje contra o Sport. :)
Aí vai o programa (cheio de comentários):
#!/usr/bin/env python
# coding: utf-8
import re, sys
from crawler import crawler
from BeautifulSoup import BeautifulSoup
class fetch(crawler):
host = 'www.gazetaesportiva.net'
request = '/campeonatos/futebol/nacional/2008/brasileirao/conteudo/desempenho.php'
if __name__ == '__main__':
# cria o crawler
doc = fetch()
# busca o documento
buffer = doc()
if not buffer:
print doc.status, doc.reason
sys.exit(1)
# armazena as listas de times e desempenho nas rodadas
name_list = []
data_list = []
# cria o soup, já convertendo as entidades HTML pra
# caracteres unicode: aacute vira "á"
soup = BeautifulSoup(buffer, convertEntities='html')
# encontra os nomes dos times
name = soup.findAll('strong')
# depois de encontrar os nomes, compilamos essa
# expressão regular que irá remover as tags
# NOTA: talvez já tenha isso no BS e eu não sei :p
junk = re.compile('</?strong>', re.IGNORECASE)
# encontra os dados dos times (pelo caracter º)
data = soup.findAll(text=re.compile('\d{1,2}[\xc2\xba]'))
# cria a lista de nomes removendo as tags
# e qualquer outro lixo
for n in name:
text = junk.sub('', str(n)).strip()
if text: name_list.append(text)
# cria a lista de desempenho por time
if len(data) % len(name_list):
print 'Oops! Problemas com os dados.'
sys.exit(1)
div = len(data) / len(name_list)
for n in range(0, len(data)+1, div):
data_list.append(data[n:n+div])
# imprime tudo :)
for k, v in zip(name_list, data_list):
print k, ', '.join(v)Além de simples e razoavelmente rápido, o Beautil Soup tem muitos recursos que permitem interpretar o conteúdo de forma eficiente, evitando o trabalho demorado de escrever um mega parser pra cada HTML que vai interpretar.
Se rodar o programa, ele mostra isso:
$ python desempenho-futebol.py Atlético/MG 11º, 13º, 15º, 7º, 12º Atlético/PR 6º, 5º, 5º, 9º, 5º Botafogo 2º, 10º, 9º, 15º, 9º Cruzeiro 2º, 2º, 1º, 1º, 2º Coritiba 2º, 8º, 7º, 8º, 13º Figueirense 9º, 4º, 12º, 11º, 16º Flamengo 1º, 3º, 2º, 2º, 1º Fluminense 11º, 17º, 19º, 20º, 20º Goiás 13º, 14º, 16º, 17º, 19º Grêmio 6º, 6º, 3º, 5º, 4º Internacional 6º, 11º, 13º, 13º, 17º Ipatinga 14º, 20º, 20º, 16º, 15º Náutico 5º, 1º, 4º, 3º, 3º Palmeiras 18º, 12º, 10º, 6º, 10º Portuguesa 9º, 16º, 18º, 19º, 14º Santos 17º, 7º, 14º, 14º, 17º São Paulo 14º, 15º, 17º, 18º, 11º Sport 18º, 17º, 11º, 10º, 6º Vasco 14º, 8º, 7º, 4º, 7º Vitória 18º, 17º, 6º, 12º, 8º
Se você for copiar e colar o código, não esqueça que esse maldito CSS do wordpress fica mexendo nas aspas. Pra resolver isso, tem os esquemas que publiquei aqui pra resolver.


[...] Só de pensar que já fiz crawler pra classificação do brasileirão… e agora o globoesporte.com tem isso: [...]