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.

Anúncios

One Comment 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 um comentário

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

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s