Herberth Amaral

Software development adventures

Criando Web crawlers em Python – Parte II

with 9 comments

Ir para  Criando Web crawlers em Python – Parte I

Ir para Criando Web crawlers em Python – Parte III

No post anterior, eu mostrei como recuperar informações básicas de uma página da Web usando urllib, urllib2 e BeautifulSoup. Neste post eu mostrarei como enviar dados via GET e POST.

Há um excelente guia sobre urllib2: o urllib2 – The Missing Manual que foi de grande valia nos meus estudos. Nele, pode-se encontrar as informações sobre envio de informações do tipo GET e POST para o servidor. Isso será útil, pois é assim que a busca do SourceForge (e da maioria dos outros portais) funcionam.

Vamos dar uma olhada na URL do na pesquisa por “Python” no SF:

http://sourceforge.net/search/?type_of_search=soft&words=python

Bem, isso indica que temos que enviar duas variáveis para o SF.net: type_of_search (sempre igual à soft) e words (que é a nossa busca). Um exemplo de código que faria essa busca poderia ser esse:

import urllib,urllib2

base_url = 'http://sourceforge.net'
busca = raw_input('Pesquisar por: ')

variaveis_get = urllib.urlencode({'type_of_search':'soft','words':busca})
req = urllib2.Request(base_url+'/search/',variaveis_get)
response = urllib2.urlopen(req).read()
print response

Se der tudo certo, você  deveráver  o código fonte da página do SF que contém os resultados da pesquisa.

Feito isso, vamos analisar como a marcação do SF é organizada na busca:

O Firebug nos ajuda a não perder tanto tempo assim analisando código. De acordo com o que pudemos obter, podemos dividir as informações que queremos dessa forma:

  • O resultado da busca está dentro de uma tabela com o id=”searchtable”.
  • Um resultado da busca está sempre dentro de um td com classe description.
  • O nome do projeto está dentro de um link dentro de um h2 dentro desse td “description”.
  • O link de download se encontra na próxima td da mesma linha da tabela.

Exibindo as informações dos projetos

Agora nós temos como buscar nossa informação e como filtra-la. Como disse no post anterior, eu iria mostrar alguns usos mais avançados do BeautifulSoup, principalmente no que diz respeito à percorrer o documento. O próximo passo será mostrar as informações dos projetos que aparecem no resultado da nossa busca. Podemos fazer isso da seguinte forma:

from BeautifulSoup import BeautifulSoup
import urllib,urllib2

base_url = 'http://sourceforge.net'
busca = raw_input('Pesquisar por: ')

variaveis_get = urllib.urlencode({'type_of_search':'soft','words':busca})
req = urllib2.Request(base_url+'/search/',variaveis_get)
response = urllib2.urlopen(req).read()

soup = BeautifulSoup(response)
# procura pela tabela com id=searchtable
tabela = soup.find('table',{'id':'searchtable'})
#retorna uma lista com todas as linhas (<tr>) da tabela
linhas_tabela = tabela.findAll('tr')

i=0

for linha in linhas_tabela:
    i+=1
    #encontra a primeira coluna (descricao) da linha
    coluna_descricao = linha.find('td')

    #o atributo contents contem uma lista com o conteudo da tag
    nome_projeto = coluna_descricao.find('a').contents[0]

    descricao_projeto = coluna_descricao.contents[2].strip()
    print 'Projeto '+str(i)+': '+nome_projeto
    print descricao_projeto
    print '--------------------------------'

Legal, não?  Isso é uma demonstração básica do poder que o BeautifulSoup tem para percorrer e extrair informações em (X)HTML. O mais interessante de tudo é que quase todos os métodos da classe BeutifulSoup.Tag retornam a própria referência, o que quer dizer que podemos fazer chains (cadeias) de comando como essas:

nome_do_primeiro_projeto_da_pesquisa = soup.find('table',{'id':'searchtable'}).findAll('tr')[0].find('td').find('a').contents[0]

Isso é realmente muito útil quando se quer economizar código. E o mais interessante de tudo: é bem legível (mas não necessariamente fácil de interpretar… quem ler seu código assim terá que ter uma boa noção do BeautifulSoup).

Baixando os arquivos do projeto

Essa parte é relativamente fácil. O SF é um serviço muito bom, até para o nosso pequeno experimento :)

A URL que o link “Download Now” aponta sofre 3 redirects até o arquivo final. Tudo isso serve para o SF determinar a sua localização e apontar o mirror mais próximo de você. Então a única coisa que precisamos fazer é passar esse link para o wget (um programa bem útil para download de arquivos na Web presente na maioria das distribuições Linux. Um clone para Windows pode ser encontrado aqui) e ele irá baixar o projeto para nós. Simples, não?

Então vamos ao código:

from BeautifulSoup import BeautifulSoup
import urllib,urllib2
from subprocess import call

base_url = 'http://sourceforge.net'
busca = raw_input('Pesquisar por: ')

variaveis_get = urllib.urlencode({'type_of_search':'soft','words':busca})
req = urllib2.Request(base_url+'/search/',variaveis_get)
response = urllib2.urlopen(req).read()

soup = BeautifulSoup(response)

# procura pela tabela com id=searchtable
tabela = soup.find('table',{'id':'searchtable'})

 #retorna uma lista com todas as linhas da tabela
linhas_tabela = tabela.findAll('tr')

i=0
links_download = []

for linha in linhas_tabela:
    i+=1
    coluna_descricao = linha.find('td')
    nome_projeto = coluna_descricao.find('a').contents[0]
    link_download = linha.find('a',{'class':'downloadnow'})['href']
    links_download.append(link_download)
    descricao_projeto = coluna_descricao.contents[2].strip()
    print 'Projeto '+str(i)+': '+nome_projeto
    print descricao_projeto
    print '--------------------------------'

opcao = int(raw_input('Qual projeto gostaria de baixar? '))
opcao_url = base_url+links_download[opcao-1]
call(['wget',opcao_url]) #chama o wget com o link para download

A única coisa que eu fiz de novo foi adicionar o link de download em uma lista e perguntar ao usuário qual projeto ele deseja baixar. Então, eu passei o link de download para o wget que fez o serviço de baixar o arquivo pra mim. Pronto! Nosso crawler de exemplo do SF.net está pronto :)

No proximo post eu mostrarei como guardar valores de sessão para percorrermos páginas protegidas por senha. See ya!

Posts relacionados:

  1. Criando Web crawlers em Python – Parte I
  2. Criando Web crawlers em Python – Parte III
  3. Criando Web crawlers (distribuidos) em Python – Parte IV

Written by Herberth Amaral

March 7th, 2010 at 11:08 am

Posted in Python,crawler

Tagged with , , ,

9 Responses to 'Criando Web crawlers em Python – Parte II'

Subscribe to comments with RSS or TrackBack to 'Criando Web crawlers em Python – Parte II'.

  1. [...] Ir para: Criando Web Crawlers em Python – Parte II [...]

  2. Estou acompanhando esta série de posts religiosamente. É interessante esta abordagem de construir algo passo a passo, é motivador aprender coisas novas a medida que se progride em algum projeto. Vejo vocês nos próximos episo… Digo, posts !

    Edmar Ferreira

    7 Mar 10 at 18:48

  3. Créu velocidade 2! (vai até o 5?)
    Mto bacana a série de posts, mesmo pra alguém q é leigo em Python como eu.

    Keep good work!

    Elvis Guimarães

    8 Mar 10 at 20:10

  4. hahahaha, depende.

    Se vc tiver usando multithread vai até a velocidade 64, ou 128 ou sei lá :P

    A minha intenção é ir até o 5º post, mas vai depender do assunto e da empolgação :)

    herberthamaral

    8 Mar 10 at 21:00

  5. [...] parte II desta série de tutoriais, eu mostrei como criar um mini crawler para o SourceForge.net, com [...]

  6. [...] Web crawlers (distribuidos) em Python – Parte IVOutros posts da série:Parte IParte IIParte IIINa parte III eu mostrei como criar um simples sistema de recuperação de informações [...]

  7. Muito bom este seu post, Herberth. Já clareou muita coisa para mim. O tema principal do meu trabalho de diplomação é recuperação da informação e vou precisar de um pequeno web crawler e python era uma das minha opções, pois é suportado pelo Google Apps Engine. Só gostaria de saber as referências que você utilizou, se não for pedir muito, afinal tenho de documentar tudo.

    De qualquer forma, já foi de muita ajuda. O início é muito complicado, há tantas possibilidades. Acho que Python rodando nos servidores Google vai ser a melhor saída. Tenho de ver como as instâncias vão representar na quota gratuita. rsrsrs, o problema agora é a base de dados. O Google Apps Engine usa um sistema de armazenamento próprio. Vou ter de fazer um benchmark, porque não sei se vai “compensar” usar um servidor remoto para fugir do padrão do GEngine.

    Muito obrigado.

    messala

    24 Jun 10 at 17:36

  8. Olá Messala,

    Eu não utilizei nenhuma referência ‘acadêmica’ no crawler, mas os seguintes conteúdos foram de muita ajuda:

    http://www.voidspace.org.uk/python/articles/urllib2.shtml (urllib2: The Missing Manual)
    http://www.crummy.com/software/BeautifulSoup/ (BeautifulSoup – documentação oficial)

    Você pode achar esses links no texto também.

    De qualquer forma, eu recomendo o uso do BeautifulSoup se você não precisar mexer com o software no futuro, pois ele está entrando em depreciação. Uma boa alternativa é o lxml: http://codespeak.net/lxml/

    Até mais!

    Herberth Amaral

    24 Jun 10 at 18:05

  9. Muito obrigado pela atenção.

    Nessa nossa área, as ferramentas que utilizamos estão sempre à mercê do desuso. Obrigo pelo conselho.

    Boa tarde e bom trabalho.

    messala

    24 Jun 10 at 18:46

Leave a Reply