crawler com beautiful soup

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.data

Basicamente, 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.


Um Comentário on “crawler com beautiful soup”

  1. coisas lunix disse:

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


Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Sair / Alterar )

Imagem do Twitter

You are commenting using your Twitter account. Sair / Alterar )

Foto do Facebook

You are commenting using your Facebook account. Sair / Alterar )

Connecting to %s

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.