Criando Web crawlers em Python – Parte I
Ir para: Criando Web Crawlers em Python - Parte II
Iniciemos com a definição de Web crawler:
Um Web crawler é um programa de computador que navega pela World Wide Web de maneira metódica e automatizada. [Wikipedia]
Os Web crawlers (ou simplesmente crawlers) têm um papel importante na nossa vida hoje. Como exemplos clássicos de Web crawlers, podemos citar o Google Bot, o Yahoo! Slurp e o MsnBot. Sem esses crawlers, não teríamos a busca do Google, do Yahoo! ou do Bing.
O objetivo dessa série de tutoriais não é ensinar criar crawlers de alta disponibilidade, alta performance e distribuídos mas mostrar como eles podem ser construidos sem muito custo ou complexidade, de forma que atenda uma necessidade específica. Entenda necessidade específica como download de imagens de um conjunto de páginas, um sistema de download de arquivos de hosts como o Rapidshare ou MegaUpload (sim, é possível!) ou uma busca e categorização de informações distribuídas entre diversos sites (como editais de concursos em portais).
Aspectos legais e ética de crawlers:
Antes de continuar lendo esta série, gostaria de informar que não é todo site que lhe dá permissão de acesso por meios de robores de busca. Procure sempre ler as políticas de uso e sempre respeite o robots.txt: se não é pra você crawlear determinada página, não o faça.
O processo:
Preste atenção aos componentes do crawler:
- Fila: pode conter uma ou mais URLs. Dependendo do tamanho da fila, a mesma pode estar no disco, ao invés de somente na memória.
- Downloader: geralmente costuma-se colocar um downloader multithreaded. No nosso primero exemplo vamos fazer um downloader singlethreaded para evitar complexidade.
- Parser: esse é o mais interessante. Ele vai extrair informações da página baixada pelo downloader segundo as especificações passadas pra ele. É pra ele que você irá dizer que quer extrair todas as imagens de uma determinada página.
- Storage: pode ser qualquer tipo de armazenamento em qualquer tipo de mídia. Não iremos persistir os dados nessa primeira parte do tutorial.
Nota-se que esse diagrama não representa um crawler de alta performance, pois ele mal diz sobre a arquitetura do mesmo, não diz sobre hardware, links de rede, paralelismo e tudo mais, mas serve com o intuito de explicar o básico do sistema.
Maos à obra: fazendo um downloader com uma fila simples
Para download de páginas e arquivos na Web, nós usaremos o urlib e a urlib2 do Python. Apesar das versões das libs, uma complementa a outra. Por exemplo, só se pode mudar os headers HTTP na urllib2 e o método urlencode só está disponível na urllib. Contudo, nós usaremos mais a urllib2. O código:
import urllib2 url = "http://www.google.com" request = urllib2.Request(url) response = urllib2.urlopen(request) document = response.read() print document
Execute esse código e se tudo der certo você verá o código fonte da página inicial do Google!
Bem, só ter o código fonte da página não é muito útil. Precisamos extrair informações dela. Uma forma de que podemos adotar é por Regex (expressão regular), mas usar regex dificultaria nosso trabalho e fugiríamos da idéia de deixar as coisas simples.
Um grande problema da Web hoje é que muitos desenvolvedores escrevem código (X)HTML mal formado e isso dificulta um pouco nossa vida. Felizmente isso não é um impedimento grave e podemos contorna-lo com o BeautifulSoup. O BeautifulSoup faz um excelente trabalho transformando o código de marcação (HTML, XML ou XHTML) em objetos que podem ser facilmente manipulados. De acordo com o esquema mostrado apresentado aqui, o BeautifulSoup faz parte do parser.
Façamos algo útil: vamos listar todos os links da página inicial do Google.
import urllib2
from BeautifulSoup import BeautifulSoup
url = "http://www.google.com"
request = urllib2.Request(url)
response = urllib2.urlopen(request)
document = response.read()
soup = BeautifulSoup(document) #normaliza o documento para que o mesmo seja acessível via objetos
links = soup.findAll('a') # retorna uma lista com todos os links do documento
for link in links:
print link
Fácil não?!
Se tudo correr bem, você deve ver uma saída igual a essa:
<a href="http://images.google.com.br/imghp?hl=pt-BR&tab=wi">Imagens</a><a href="http://video.google.com.br/?hl=pt-BR&tab=wv">Vídeos</a><a href="http://maps.google.com.br/maps?hl=pt-BR&tab=wl">Mapas</a><a href="http://news.google.com.br/nwshp?hl=pt-BR&tab=wn">Notícias</a><a href="http://www.orkut.com/Home.aspx?hl=pt-BR&tab=w0">Orkut</a><a href="http://mail.google.com/mail/?hl=pt-BR&tab=wm">Gmail</a><a href="http://www.google.com.br/intl/pt-BR/options/" style="text-decoration:none"><u>mais</u> »</a><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.com.br/ig%3Fhl%3Dpt-BR%26source%3Diglk&usg=AFQjCNEufhwNAC9POZqcS5r7r07CUPbvAA">iGoogle</a><a href="/preferences?hl=pt-BR">Configurações da pesquisa</a><a href="https://www.google.com/accounts/Login?hl=pt-BR&continue=http://www.google.com.br/">Fazer login</a><a href="/search?q=Vancouver+2010&ct=olympics10-sskating-hp&oi=ddle"><img src="/logos/olympics10-sskating-hp.png" width="523" height="170" border="0" alt="Vancouver 2010" title="Vancouver 2010" id="logo" onload="window.lol&&lol()" /></a><a href="/advanced_search?hl=pt-BR">Pesquisa avançada</a><a href="/language_tools?hl=pt-BR">Ferramentas de idiomas</a><a href="/intl/pt-BR/ads/">Soluções de publicidade</a><a href="/services/">Soluções empresariais</a><a href="/intl/pt-BR/about.html">Tudo sobre o Google</a><a href="http://www.google.com/ncr">Google.com in English</a><a href="/intl/pt-BR/privacy.html">Privacidade</a><a href="http://images.google.com.br/imghp?hl=pt-BR&tab=wi">Imagens</a><a href="http://video.google.com.br/?hl=pt-BR&tab=wv">Vídeos</a><a href="http://maps.google.com.br/maps?hl=pt-BR&tab=wl">Mapas</a><a href="http://news.google.com.br/nwshp?hl=pt-BR&tab=wn">Notícias</a><a href="http://www.orkut.com/Home.aspx?hl=pt-BR&tab=w0">Orkut</a><a href="http://mail.google.com/mail/?hl=pt-BR&tab=wm">Gmail</a><a href="http://www.google.com.br/intl/pt-BR/options/" style="text-decoration:none"><u>mais</u> »</a><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.com.br/ig%3Fhl%3Dpt-BR%26source%3Diglk&usg=AFQjCNEufhwNAC9POZqcS5r7r07CUPbvAA">iGoogle</a><a href="/preferences?hl=pt-BR">Configurações da pesquisa</a><a href="https://www.google.com/accounts/Login?hl=pt-BR&continue=http://www.google.com.br/">Fazer login</a><a href="/search?q=Vancouver+2010&ct=olympics10-sskating-hp&oi=ddle"><img src="/logos/olympics10-sskating-hp.png" width="523" height="170" border="0" alt="Vancouver 2010" title="Vancouver 2010" id="logo" onload="window.lol&&lol()" /></a><a href="/advanced_search?hl=pt-BR">Pesquisa avançada</a><a href="/language_tools?hl=pt-BR">Ferramentas de idiomas</a><a href="/intl/pt-BR/ads/">Soluções de publicidade</a><a href="/services/">Soluções empresariais</a><a href="/intl/pt-BR/about.html">Tudo sobre o Google</a><a href="http://www.google.com/ncr">Google.com in English</a><a href="/intl/pt-BR/privacy.html">Privacidade</a>
Na verdade, a linha
links = soup.findAll('a')
não retorna uma lista de strings, mas uma lista de objetos que representam tags em HTML (classe BeautifulSoup.Tag). Logo, há outras propriedades e métodos que podemos explorar. Digamos que você só queira as URLs dos links e não está interessado no texto ou na marcação. O nosso código ficaria assim:
import urllib2
from BeautifulSoup import BeautifulSoup
url = "http://www.google.com"
request = urllib2.Request(url)
response = urllib2.urlopen(request)
document = response.read()
soup = BeautifulSoup(document) #normaliza o documento para que o mesmo seja acessível via objetos
links = soup.findAll('a') # retorna uma lista com todos os links do documento
for link in links:
print link['href']
Como saída, você pode obter algo do tipo:
http://images.google.com.br/imghp?hl=pt-BR&tab=wi http://video.google.com.br/?hl=pt-BR&tab=wv http://maps.google.com.br/maps?hl=pt-BR&tab=wl http://news.google.com.br/nwshp?hl=pt-BR&tab=wn http://www.orkut.com/Home.aspx?hl=pt-BR&tab=w0 http://mail.google.com/mail/?hl=pt-BR&tab=wm http://www.google.com.br/intl/pt-BR/options/ /url?sa=p&pref=ig&pval=3&q=http://www.google.com.br/ig%3Fhl%3Dpt-BR%26source%3Diglk&usg=AFQjCNEufhwNAC9POZqcS5r7r07CUPbvAA /preferences?hl=pt-BR https://www.google.com/accounts/Login?hl=pt-BR&continue=http://www.google.com.br/ /search?q=Vancouver+2010&ct=olympics10-sskating-hp&oi=ddle /advanced_search?hl=pt-BR /language_tools?hl=pt-BR /intl/pt-BR/ads/ /services/ /intl/pt-BR/about.html http://www.google.com/ncr /intl/pt-BR/privacy.html
Como você pode ver, o BeautifulSoup é quase uma mãe quando o assunto é extrair informações de HTML
.
No próximo tutorial, eu abordarei usos mais avançados do BeautifulSoup e mostrarei como usar os métodos GET e POST e também mostrarei uma pequena aplicação para procurar e baixar arquivos do SourceForge.net. Até o próximo!
Criando screencasts no Linux
Eu vi algumas pessoas reclamando sobre a dificuldade de criar screencasts usando Linux. É, eu também tive algumas dificuldades. Nenhuma das ferramentas que eu consegui encontrar com minhas buscas não resolviam meu problema:
- Istanbul - Bonitinho, parece leve, grava legal, mas simplesmente dá um erro de IO (não entendi direito qual era o erro ) e não salva.
- xvidcap - Levíssimo, completo, mas tem problema com o PulseAudio e não grava o áudio do microfone. Tentei inicializa-lo com o comando padsp xvidcap, mas também não resolveu: mesmo chiado no som.
- recordMyDesktop - Grava áudio normal, mas as imagens tinham uma qualidade horrível. Parecia que ele atualizava uma parte da tela e esquecia da outra. Resultado: eu gravava um teste no VIM na linha de comando (preta) e quando eu passava pro GMail (verde) a tela ainda continuava preta...
Não sei o por quê, mas nem todos os programas que vem no Linux vêm com as configurações mais comuns já de cara. O problema é que eu não percebi que o recordMyDesktop encaixaria perfeitamente pra mim se ele já viesse com uma opção já marcada desde o início:
Estranho, não? Eu pensava que marcar "Full shots at every frame" resolveria meu problema, mas, inexplicavelmente, o "Encode On the Fly" resolveu. Apesar da tooltip dizer que essa opção consome mais poder de processamento, eu não notei tanto. A qualidade do vídeo ficou impecável e eu estou com os efeitos no máximo
Se após gravado o screencast você desejar edita-lo ou converte-lo, há uma gama de softwares para Linux mesmo que fazem isso. Para conversão eu uso muito o ffmpeg (não conheço nenhum outro melhor e mais completo) e me recomendaram o Avidemux para edição de vídeo. A única coisa que eu sinto falta agora é algo que coloque os caracteres digitados na tela e que destaque o clique do mouse.
See ya!
Dica rapida: conversao de bases em JavaScript
Essa é uma dica extremamente simples mas que poderia ter salvo um tempo em um dos nossos CodingDojo. Trata-se de conversão de bases em JavaScript.
(14).toString(2) // decimal para binário. Saída: 1110 (0xf3).toString(10) //hexadecimal (início 0x) para decimal. Saída: 243 (0324).toString(16) //octal (inicio 0) para hexadecimal. Saída: d4 (15276).toString(36) // decimal para base 36 (máximo possível). Saída: bsc
Legal, não?
Créditos da dica: Elvis.
Flex For Kids foi 10!
Depois de um dia inteiro de correria, muita palestra e principalmente comida, estou aqui para contar um pouco do Flex For Kids para vocês.
Infelizmente, perdemos uma palestra que parecia ser bem legal: Desenvolvimento Multi-touch com AIR 2.0. Tivemos problemas com a conexão e iniciamos meio atrasados. Bem que a porta de saída poderia ser a 80 mesmo... evitaria muitos problemas.
Conseguimos pegar a palestra do Igor Musardo (Construa painéis administrativos em Flex integrados com ASP.NET MVC) bem no início, quando ele começou a falar sobre ASP.NET MVC e Flex. Ele mostrou um pequeno sistema para gerenciamento de conteúdo usando o Flex 3 e o ASP.NET MVC como backend e usou o JSON como formato de comunicação. A maioria dos presentes não tinha familiaridade com .NET, mas serviu pra mostrar um pouco da tecnologia. Bem interessante a palestra, mas eu fiquei curioso com o fato dele não usar AMF para isso. Devido à alguns problemas técnicos com a transmissão, a palestra do Musardo acabou atrasando um pouco, mas nada grave.
A palestra a seguir foi a do Mário Junior: Swiz Framework: MVC Simples e Poderoso para projetos Flex/AIR. Como o Mario mesmo disse, o Swiz é extremamente simples e leve, no entanto a palestra dele serviu para mostrar como eu subutilizo os recursos que o Swiz oferece. Ele é muito mais poderoso que eu pensava. Valeu muito pra mim e pra galera da Infobits. Muito boa a palestra dele.
Como eu estava na organização e nós tínhamos que trazer o almoço para a Unimontes, eu acabei perdendo a palestra do Eberton Consolim: Flex e VOIP: Adicione essa tecnologia em suas aplicações. Segundo a galera que assistiu, a palestra foi excelente, mas infelizmente terei que aguardar o acesso às gravações para ter certeza
A próxima palestra logo após o almoço foi a do Daniel Lopes: Desktop com HTML, Javascript e Adobe AIR. A palestra foi muito bem ministrada: muito conceito, muita idéia e pouca explicação de código e ele incrivelmente conseguiu fazer um hands-on sem muitas delongas. Incrível. Excelente palestra.
A palestra da Gabriela teria sido mais interessante se eu entendesse um pouco mais de User eXperience. No entanto, foi bom ter uma palestra no-code no meio de tantas. Aliás, foi bom ter visto uma mulher no meio de tanto marmanjo
. Mesmo assim, foi proveitosa.
O Eric Calvancanti assumiu a missão de desmistificar o Cairngorm. E posso dizer que ele o fez com muito sucesso! Segundo o Vedovelli, até a avó dele entenderia o que o Eric quis passar. Foi a apresentação mais didática que tivemos, apesar do Cairngorm ser o framework mais complexo apresentado hoje.
A palestra do Vedovelli foi uma das mais esperadas. Muito conhecido pelos seus screencasts e sua irreverência, o Ved, como costuma ser chamado, se tornou um dos ícones dos Flexers nacionais. Ele explicou como funciona a arquitetura de uma aplicação usando o framework Mate. O framework é interessante e comparável em muitos pontos com o Swiz. Muito boa apresentação.
O "vírus da bactéria" que o cachorro do Igor Costa não consegue ver deixou a sua apresentação muito divertida, além de informativa! O Igor é uma das maiores referencias em Flex e Java no Brasil e sua palestra foi memorável. Eu não saco muita coisa de JEE, mas a palestra dele foi bem inteligível.
E por último e com a melhor palestra do dia, a do Beck Novaes. Ele deu uma geral sobre a plataforma Adobe de desenvolvimento de RIAs: Flash, Flex, Flash Builder e Flash Catalyst. A palestra foi incrível. Ele tem um mix de explicação extremamente fácil de entender com informação útil. Deveria ter sido a primeira palestra do dia, com toda certeza.
Nossa reunião na Unimontes teve uma audiência de 15 pessoas e contou com a organização e apoio da Infobits e da Gerência de Tecnologia da Informação da Unimontes. Queria agradecer a todos que vieram e prestigiaram o evento. Também gostaria de dar os parabéns a todos que tiraram o escorpião do bolso e doaram para o Cotolengo. Muito bacana! A seguir, as fotos do evento:
Eu vou participar do Flex For Kids. E voce?
Como eu bloguei em outro blog anteriormente, eu vou participar do Flex For Kids!
Basicamente, o evento é praticamente uma maratona de palestras: nove palestras de uma hora cada em exatamente nove horas de duração, de 8:00 às 17:00, e contará com palestrantes da comunidade Flexer Brasiliera.
Todo dinheiro arrecadado com as inscrições será destinado à Cotolengo, uma instituição do Mato Grosso do Sul que acolhe pessoas com necessidades especiais.
Nós, da Infobits, conseguimos reservar o auditório do Centro de Ciências Exatas e Tecnológicas para acomodar os participantes do evento, estamos organizando algumas outras coisas (como o almoço, a alimentação no resto do dia e a inscrição no evento) e temos 8 pessoas já confirmadas (o número vai subir até amanhã).
Só lembrando: se você quer participar do Flex For Kids conosco, ainda tem tempo! Nos procure na Infobits*, mande email, sinal de fumaça ou comente esse post
*Sala 10A do Centro de Ciências Exatas e Tecnológicas. Perdido? Veja no Google Maps.
