<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>Herberth Amaral &#187; Python</title> <atom:link href="http://herberthamaral.com/tag/python/feed/" rel="self" type="application/rss+xml" /><link>http://herberthamaral.com</link> <description>Software development adventures</description> <lastBuildDate>Thu, 26 Aug 2010 13:59:42 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.0.1</generator> <item><title>Brincando com monkey patching</title><link>http://herberthamaral.com/2010/07/brincando-com-monkey-patching/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=brincando-com-monkey-patching</link> <comments>http://herberthamaral.com/2010/07/brincando-com-monkey-patching/#comments</comments> <pubDate>Sat, 10 Jul 2010 15:52:58 +0000</pubDate> <dc:creator>Herberth Amaral</dc:creator> <category><![CDATA[Misc]]></category> <category><![CDATA[Python]]></category> <category><![CDATA[monkey patch]]></category> <category><![CDATA[produtividade]]></category><guid isPermaLink="false">http://herberthamaral.com/?p=565</guid> <description><![CDATA[Segundo a Wikipedia, monkey patch é uma técnica utilizada para modificar atributos, funções e métodos em tempo de execução, ou seja, sem precisar mexer na implementação. Somente algumas linguagens dinâmicas suportam monkey patching, como Ruby, JavaScript, Smalltalk e Perl. Há linguagens dinâmicas que não tem suporte, como é o caso do PHP (apesar de ter [...]]]></description> <content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"> <a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fherberthamaral.com%2F2010%2F07%2Fbrincando-com-monkey-patching%2F"> <img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fherberthamaral.com%2F2010%2F07%2Fbrincando-com-monkey-patching%2F&amp;source=HerberthAmaral&amp;style=normal" height="61" width="50" /> </a></div><p>Segundo a Wikipedia, <em>monkey patch</em> é uma técnica utilizada para modificar atributos, funções e métodos em tempo de execução, ou seja, sem precisar mexer na implementação.</p><p>Somente algumas linguagens dinâmicas suportam monkey patching, como Ruby, JavaScript, Smalltalk e Perl. Há linguagens dinâmicas que não tem suporte, como é o caso do PHP (apesar de ter algumas formas de obter um resultado parecido).</p><p>Eis um exemplo simples de patching com Python:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> sayHiToMe<span style="color: black;">&#40;</span>me<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Hi, '</span>+me<br /> <br /> sayHiToMe<span style="color: black;">&#40;</span><span style="color: #483d8b;">'Herberth'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Hi, Herberth</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">def</span> sayHello<span style="color: black;">&#40;</span>me<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Hello, '</span>+me<br /> <br /> sayHiToMe = sayHello<br /> <br /> sayHiToMe<span style="color: black;">&#40;</span><span style="color: #483d8b;">'Herberth'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Hello, Herberth</span></div></div><p>Isto é possível porque o Python trata suas funções e métodos como objetos. Tanto é que você pode chamar uma função/método utilizando o método __call__:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> sayHiToMe<span style="color: black;">&#40;</span>me<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Hi, '</span>+me<br /> <br /> sayHiToMe.<span style="color: #0000cd;">__call__</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Herberth'</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;">#Hi, Herberth</span></div></div><p>Uma coisa mais interessante é modificar métodos de classe em tempo de execução e a modificação ficar valendo para todos os objetos:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> Teste:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> meuTeste<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Testando...'</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">def</span> meuOutroTeste<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Testando denovo...'</span><br /> <br /> primeiroTeste = Teste<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> primeiroTeste.<span style="color: black;">meuTeste</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;">#Testando...</span><br /> <br /> Teste.<span style="color: black;">meuTeste</span> = meuOutroTeste<br /> primeiroTeste.<span style="color: black;">meuTeste</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;">#Testando denovo...</span></div></div><p>Este é um dos motivos pelos quais você tem que passar a referência do objeto para cada método da classe <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p><p>Monkey patching pode ser muito útil quando necessitamos de um mock/stub para testar uma determinada classe/método:  você pode criar o método que vai substituir o médoto em questão sem precisar perder a referência do método original. Exemplo:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">class</span> Email:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> sendMail<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,<span style="color: #ff7700;font-weight:bold;">from</span>,to,subject,message<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Enviando email...'</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">mailSent</span> = <span style="color: #008000;">True</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">def</span> Cliente:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> cadastro<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,nome,telefone,<span style="color: #dc143c;">email</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># salva o cliente no banco de dados e no fim envia um email</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">mail</span> = Email<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">mail</span>.<span style="color: black;">send</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'admin@loja.com'</span>,<span style="color: #483d8b;">'cliente@teste.com'</span>,<span style="color: #483d8b;">'blah'</span>,<span style="color: #483d8b;">'blah blah!'</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #808080; font-style: italic;"># não queremos que o método da classe Email apresentada acima envie um email</span><br /> <span style="color: #808080; font-style: italic;"># a cada de cadastro do cliente. Por isso, vamos fazer um patch para o método sendMail.</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">def</span> sendFakeMail<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,<span style="color: #ff7700;font-weight:bold;">from</span>,to,subject,message<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">mailSent</span> = <span style="color: #008000;">True</span><br /> <br /> originalMail = Email.<span style="color: black;">sendMail</span> <span style="color: #808080; font-style: italic;">#salva a referencia original de sendMail</span><br /> Email.<span style="color: black;">sendMail</span> = sendFakeMail<br /> c = Cliente<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> c.<span style="color: black;">cadastro</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Herberth'</span>,<span style="color: #483d8b;">'999-9999'</span>,<span style="color: #483d8b;">'meu@email.com'</span><span style="color: black;">&#41;</span><br /> <span style="color: #ff7700;font-weight:bold;">assert</span> c.<span style="color: black;">mail</span>.<span style="color: black;">mailSent</span> <span style="color: #808080; font-style: italic;">#verifica se o email foi enviado</span><br /> Email.<span style="color: black;">sendMail</span> = originalMail <span style="color: #808080; font-style: italic;"># restaura o sendMail original</span></div></div><p>Legal, não? <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p><p>Sem posts relacionados.</p>]]></content:encoded> <wfw:commentRss>http://herberthamaral.com/2010/07/brincando-com-monkey-patching/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Criando Web crawlers (distribuidos) em Python &#8211; Parte IV</title><link>http://herberthamaral.com/2010/05/criando-web-crawlers-distribuidos-em-python-parte-iv/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=criando-web-crawlers-distribuidos-em-python-parte-iv</link> <comments>http://herberthamaral.com/2010/05/criando-web-crawlers-distribuidos-em-python-parte-iv/#comments</comments> <pubDate>Thu, 06 May 2010 12:31:12 +0000</pubDate> <dc:creator>Herberth Amaral</dc:creator> <category><![CDATA[Python]]></category> <category><![CDATA[crawler]]></category> <category><![CDATA[computação científica]]></category> <category><![CDATA[pyro]]></category> <category><![CDATA[sistemas distribuídos]]></category><guid isPermaLink="false">http://herberthamaral.com/?p=362</guid> <description><![CDATA[Outros posts da série: Parte I Parte II Parte III Na parte III eu mostrei como criar um simples sistema de recuperação de informações usando em áreas protegidas por senha, usando o legendas.tv como exemplo. Neste post, eu irei mostrar como criar um crawler distribuindo-o por vários computadores da sua rede (ou colocar várias instâncias [...]]]></description> <content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"> <a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fherberthamaral.com%2F2010%2F05%2Fcriando-web-crawlers-distribuidos-em-python-parte-iv%2F"> <img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fherberthamaral.com%2F2010%2F05%2Fcriando-web-crawlers-distribuidos-em-python-parte-iv%2F&amp;source=HerberthAmaral&amp;style=normal" height="61" width="50" /> </a></div><p>Outros posts da série:</p><ul><li><a href="http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i/">Parte I</a></li><li><a href="http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-ii/">Parte II</a></li><li><a href="http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-iii/">Parte III</a></li></ul><p>Na <a href="http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-iii/">parte III</a> eu mostrei como criar um simples sistema de recuperação de informações usando em áreas protegidas por senha, usando o <a href="http://legendas.tv">legendas.tv</a> como exemplo. Neste post, eu irei mostrar como criar um crawler distribuindo-o por vários computadores da sua rede (ou colocar várias instâncias rodando na mesma máquina).</p><p>Sistemas distribuídos sempre foi um dos meus assuntos favoritos à estudar. Ter à minha disposição um cluster para poder realizar alguns experimentos, ou desenvolver um software para rodar de forma distribuída sem precisar aumentar a complexidade do SO sempre me chamou atenção.</p><div><p>Neste post, eu vou mostrar como o PyRO (Python Remote Object) e seus artefatos funcionam e como tirar proveito deles para criar um crawler distribuído de forma bem fácil.</p><p>O PyRO tem uma arquitetura parecida com a RMI do Java e que lembra um pouco o CORBA. A diferença é que o PyRO tem uma arquitetura interna bem mais simples e a sua programação é bem menos verbosa, já que você não precisa de escrever quilos de código pra ter um exemplo funcional.</p><h4>1 &#8211; Arquitetura básica</h4><div id="attachment_392" class="wp-caption aligncenter" style="width: 310px"><a href="http://herberthamaral.com/wp-content/uploads/2010/05/PyRO.png"><img class="size-medium wp-image-392" title="Arquitetura básica de um sistema distribuído com PyRO" src="http://herberthamaral.com/wp-content/uploads/2010/05/PyRO-300x78.png" alt="Arquitetura básica de um sistema distribuído com PyRO" width="300" height="78" /></a><p class="wp-caption-text">Arquitetura básica de um sistema distribuído com PyRO</p></div><ol><li>PyRO server: responsável por instanciar o objeto e o distribuir pela rede. É importante notar que ele <strong>não </strong>instancia um novo objeto a cada requisição ou pra cada cliente: a mesma instância do objeto é utilizada <strong>sempre</strong> (à menos que você especifique o contrário).</li><li>Rede: essa parte é obvia <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /></li><li>Client: consome a &#8220;instância&#8221; do objeto criado pelo server</li></ol></div><p>Falando como um programador, a estrutura acima ficaria mais ou menos assim:</p><p>Código do servidor:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> Pyro.<span style="color: black;">core</span><br /> <br /> <span style="color: #808080; font-style: italic;">#objeto que será compartilhado</span><br /> <span style="color: #ff7700;font-weight:bold;">class</span> SharedObject<span style="color: black;">&#40;</span>Pyro.<span style="color: black;">core</span>.<span style="color: black;">ObjBase</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; Pyro.<span style="color: black;">core</span>.<span style="color: black;">ObjBase</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> remoteMethod<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,message<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">'Olá '</span>+message<br /> <br /> <span style="color: #ff7700;font-weight:bold;">class</span> Main:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; Pyro.<span style="color: black;">core</span>.<span style="color: black;">initServer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; daemon = Pyro.<span style="color: black;">core</span>.<span style="color: black;">Daemon</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; objeto = SharedObject<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;">#cria a instância do objeto</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; uri = daemon.<span style="color: black;">connect</span><span style="color: black;">&#40;</span>SharedObject<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,<span style="color: #483d8b;">'obj'</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Porta do daemon'</span>,daemon.<span style="color: black;">port</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'URI do Objeto'</span>,uri<br /> &nbsp; &nbsp; &nbsp; &nbsp; daemon.<span style="color: black;">requestLoop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">if</span> __name__==<span style="color: #483d8b;">'__main__'</span>:<br /> &nbsp; &nbsp; Main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></div><p>Código do cliente:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> Pyro.<span style="color: black;">core</span><br /> <br /> objeto = Pyro.<span style="color: black;">core</span>.<span style="color: black;">getProxyForURI</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'PYROLOC://localhost:7766/obj'</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #808080; font-style: italic;">#vc pode manipular os objetos como se eles estivessem locais</span><br /> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Servidor retornou:&quot;</span>+objeto.<span style="color: black;">remoteMethod</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Herberth'</span><span style="color: black;">&#41;</span></div></div><p>Simples, não? Basta colocar o cliente pra rodar logo depois que o servidor for iniciado.  Os objetos distribuídos com o PyRO tem somente uma característica que importante notar:  você consegue compartilhar objetos normalmente, mas não consegue acessar suas propriedades diretamente. Se você precisar acessar uma propriedade, você terá que criar um getter/setter para essa propriedade (eu também achei meio feio, mas nem tudo é perfeito <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p><p>Se você tiver o olho afiado vai perceber que à medida que mudamos de servidor precisamos dar um jeito de mudar o nosso script cliente pra atender à nova mudança. E se você tiver múltiplos servidores de objetos, terá que especificar cada um nos clientes. Isso, junto com outros motivos, podem criar complicações. Uma forma de resolver isso é com o <strong>PyRO Nameserver.</strong></p><h4>2 &#8211; PyRO Nameserver.</h4><p>O principal papel do servidor de nomes é tirar a responsabilidade dos clientes saberem onde estão os seus servers. Os clientes devem ser os mais simples possível.</p><p>O servidor de nomes do PyRO na verdade são dois servidores: um servidor TCP/IP e um listener de broadcast. O listener broadcast serve para que os clientes descubram a localização do servidor de nomes e para que os servidores publiquem seus objetos.</p><p>Numa arquitetura com servidor de nomes, nosso sistema ficaria mais ou menos assim:</p><div id="attachment_394" class="wp-caption aligncenter" style="width: 616px"><a href="http://herberthamaral.com/wp-content/uploads/2010/05/pyro_ns.png"><img class="size-full wp-image-394" title="PyRO nameserver" src="http://herberthamaral.com/wp-content/uploads/2010/05/pyro_ns.png" alt="PyRO nameserver" width="606" height="351" /></a><p class="wp-caption-text">Arquitetura hipotética usando o nameserver do PyRO</p></div><p>O nameserver deve ser iniciado antes dos servidores e antes dos clientes da sua aplicação. Para inicia-lo execute o comando <em>python -m Pyro.naming</em> ou execute-o diretamente digitando <em>pyro-ns </em> ou <em>pyro-ns.cmd</em> se você tiver usando Windows.</p><p>Eis um exemplo simples de sistema distribuído usando PyRO e o PyRO-ns:</p><p>Cliente:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> Pyro.<span style="color: black;">core</span><br /> <br /> objeto = Pyro.<span style="color: black;">core</span>.<span style="color: black;">getProxyForURI</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'PYRONAME://obj'</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Servidor retornou:&quot;</span>+objeto.<span style="color: black;">remoteMethod</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Herberth'</span><span style="color: black;">&#41;</span></div></div><p>Servidor:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> Pyro.<span style="color: black;">core</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> Pyro.<span style="color: black;">naming</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">class</span> SharedObject<span style="color: black;">&#40;</span>Pyro.<span style="color: black;">core</span>.<span style="color: black;">ObjBase</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; said = <span style="color: #008000;">False</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; Pyro.<span style="color: black;">core</span>.<span style="color: black;">ObjBase</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> isSaid<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">self</span>.<span style="color: black;">said</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> remoteMethod<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,message<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">said</span> = <span style="color: #008000;">True</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">'Olá '</span>+message<br /> <br /> <span style="color: #ff7700;font-weight:bold;">class</span> Main:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; Pyro.<span style="color: black;">core</span>.<span style="color: black;">initServer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; daemon = Pyro.<span style="color: black;">core</span>.<span style="color: black;">Daemon</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; ns = Pyro.<span style="color: black;">naming</span>.<span style="color: black;">NameServerLocator</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">getNS</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; daemon.<span style="color: black;">useNameServer</span><span style="color: black;">&#40;</span>ns<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;">#publica o servidor no nameserver</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; objeto = SharedObject<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; uri = daemon.<span style="color: black;">connect</span><span style="color: black;">&#40;</span>SharedObject<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,<span style="color: #483d8b;">'obj'</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Porta do daemon'</span>,daemon.<span style="color: black;">port</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'URI do Objeto'</span>,uri<br /> &nbsp; &nbsp; &nbsp; &nbsp; daemon.<span style="color: black;">requestLoop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">if</span> __name__==<span style="color: #483d8b;">'__main__'</span>:<br /> &nbsp; &nbsp; Main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></div><p>Pouca coisa mudou no código, mas agora você não precisa especificar manualmente a localização do seu objeto: o nameserver faz o serviço pra você.</p><p>A inicialização do servidor e do cliente fica um pouco mais lenta depois que se passa a utilizar o servidor de nomes. O tempo extra é devido à busca do servidor de nomes no início da execução do cliente e do servidor.</p><p>Putz, falei demais sobre o PyRO, mas ainda tem muita coisa que eu não falei e que pode ser visto na documentação oficial. Agora vou abordar um pouco de como distribuir nosso crawler através dele.</p><h4>3 &#8211; Distribuindo seu crawler</h4><p>O crawler nada mais será do que um objeto distribuído. Sim, só isso <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p><p>A teoria pode ser fácil, mas há algumas considerações que devem ser feitas em um crawler usando a abordagem distribuída:</p><ul><li>Como dividir o trabalho entre os clientes/peers de forma eficiente?</li><li>Como assegurar que os crawlers não baixem a mesma página duas vezes?</li><li>O que acontece com o controle de concorrência quando usamos um paradigma distribuído?</li><li>Sobre single points of failure: se o servidor morre, os clientes não podem fazer nada. O que fazer nesses casos?</li></ul><p>Infelizmente, eu não posso responder todos esses aspectos. Muita pesquisa baseada nessas perguntas têm sido feita e se você vai ficar impressionado se quiser aprofundar mesmo no assunto (como eu tou fazendo pro meu TCC).</p><p>A princípio, vamos fazer um crawler simples, que obtém todas as páginas de um determinado domínio, reporta as páginas baixadas e os links encontrados nas respectivas páginas. Já vimos como usar o BeautifulSoup e como criar crawlers básicos em outros posts. Aqui segue o exemplo de um pra usarmos na versão distribuída:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;">#crawl.py =&gt; salve com esse nome, ok?</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> Pyro.<span style="color: black;">core</span><br /> <span style="color: #ff7700;font-weight:bold;">from</span> BeautifulSoup <span style="color: #ff7700;font-weight:bold;">import</span> BeautifulSoup<br /> <br /> <span style="color: #ff7700;font-weight:bold;">class</span> Crawl<span style="color: black;">&#40;</span>Pyro.<span style="color: black;">core</span>.<span style="color: black;">ObjBase</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; base_url = <span style="color: #483d8b;">&quot;http://sourceforge.net&quot;</span><br /> &nbsp; &nbsp; queue = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; downloaded_links = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><br /> &nbsp; &nbsp; links_in_process = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; Pyro.<span style="color: black;">core</span>.<span style="color: black;">ObjBase</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">queue</span>.<span style="color: black;">extend</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">getLinksAndTitle</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">base_url</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'links'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> getLinksAndTitle<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,url<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#eliminar busca em dominios externos</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>.<span style="color: black;">isLinkInDomain</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> url.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://&quot;</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; req = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">base_url</span>+url<span style="color: black;">&#41;</span><br /> <br /> &nbsp; &nbsp; &nbsp; &nbsp; response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; soup = BeautifulSoup<span style="color: black;">&#40;</span>response<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; a = soup.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; links = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> a:<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; link = i.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'href'</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> link <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #008000;">self</span>.<span style="color: black;">isLinkInDomain</span><span style="color: black;">&#40;</span>link<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; links.<span style="color: black;">append</span><span style="color: black;">&#40;</span>i.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'href'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">'links'</span>:links,<span style="color: #483d8b;">'title'</span>:soup.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'title'</span><span style="color: black;">&#41;</span>.<span style="color: black;">text</span><span style="color: black;">&#125;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> getNextLinkToDownload<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">queue</span>.<span style="color: #0000cd;">__len__</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> == <span style="color: #ff4500;">0</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; link = <span style="color: #008000;">self</span>.<span style="color: black;">queue</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">del</span> <span style="color: #008000;">self</span>.<span style="color: black;">queue</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">links_in_process</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>link<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> link<br /> <br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> reportDownloadedLink<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,link,title<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;&quot;&quot;<br /> &nbsp; &nbsp; &nbsp; &nbsp; Reporta um link baixado e seu respectivo titulo<br /> &nbsp; &nbsp; &nbsp; &nbsp; &quot;&quot;&quot;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> link <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">links_in_process</span> <span style="color: #ff7700;font-weight:bold;">and</span> \<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>.<span style="color: black;">downloaded_links</span>.<span style="color: black;">has_key</span><span style="color: black;">&#40;</span>link<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">downloaded_links</span><span style="color: black;">&#91;</span>link<span style="color: black;">&#93;</span> = title<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#tira o link da fila de processamento</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">del</span> <span style="color: #008000;">self</span>.<span style="color: black;">links_in_process</span><span style="color: black;">&#91;</span><span style="color: #008000;">self</span>.<span style="color: black;">links_in_process</span>.<span style="color: black;">index</span><span style="color: black;">&#40;</span>link<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> <br /> <br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> addLinks<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,links<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> link <span style="color: #ff7700;font-weight:bold;">in</span> links:<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> link <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">queue</span> <span style="color: #ff7700;font-weight:bold;">and</span> \<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; link <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">downloaded_links</span> <span style="color: #ff7700;font-weight:bold;">and</span> \<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; link <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">links_in_process</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">queue</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>link<span style="color: black;">&#41;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> isLinkInDomain<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,link<span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span>link.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://&quot;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> \<br /> &nbsp; &nbsp; &nbsp; &nbsp; link.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">base_url</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">or</span> \<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">not</span> link.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://'</span><span style="color: black;">&#41;</span></div></div><p>No meu caso, eu estou usando o SourceForge.net por que ele possui um robots.txt bem amigável e é um bom exemplo. Esse exemplo é bem simples (pra uma versão distribuída), mas serve perfeitamente pra ilustrar um crawler trabalhando de forma descentralizada.<br /> Vamos ao server:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> Pyro.<span style="color: black;">core</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> Pyro.<span style="color: black;">naming</span><br /> <span style="color: #ff7700;font-weight:bold;">from</span> crawl <span style="color: #ff7700;font-weight:bold;">import</span> Crawl <span style="color: #808080; font-style: italic;">#nosso crawler</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">class</span> Main:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; Pyro.<span style="color: black;">core</span>.<span style="color: black;">initServer</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; daemon = Pyro.<span style="color: black;">core</span>.<span style="color: black;">Daemon</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; ns = Pyro.<span style="color: black;">naming</span>.<span style="color: black;">NameServerLocator</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">getNS</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; daemon.<span style="color: black;">useNameServer</span><span style="color: black;">&#40;</span>ns<span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;">#publica o servidor no nameserver</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; objeto = Crawl<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; uri = daemon.<span style="color: black;">connect</span><span style="color: black;">&#40;</span>objeto,<span style="color: #483d8b;">'crawl'</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Porta do daemon'</span>,daemon.<span style="color: black;">port</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'URI do Objeto'</span>,uri<br /> &nbsp; &nbsp; &nbsp; &nbsp; daemon.<span style="color: black;">requestLoop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">if</span> __name__==<span style="color: #483d8b;">'__main__'</span>:<br /> &nbsp; &nbsp; Main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></div><p>Nenhuma novidade no servidor. Apenas colocamos a instância do crawler como objeto distribuído.<br /> Agora o código do cliente:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> Pyro.<span style="color: black;">core</span><br /> <br /> crawl = Pyro.<span style="color: black;">core</span>.<span style="color: black;">getProxyForURI</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'PYRONAME://crawl'</span><span style="color: black;">&#41;</span><br /> <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br /> &nbsp; &nbsp; link = crawl.<span style="color: black;">getNextLinkToDownload</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> link:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">break</span> <span style="color: #808080; font-style: italic;">#nenhum link encontrado. fim do crawling</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> link.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'download'</span><span style="color: black;">&#41;</span>: <span style="color: #808080; font-style: italic;">#so queremos paginas, sem baixar arquivos</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">continue</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Obtendo link: '</span>,link<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">try</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; result = crawl.<span style="color: black;">getLinksAndTitle</span><span style="color: black;">&#40;</span>link<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; crawl.<span style="color: black;">reportDownloadedLink</span><span style="color: black;">&#40;</span>link,result<span style="color: black;">&#91;</span><span style="color: #483d8b;">'title'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; &nbsp; &nbsp; crawl.<span style="color: black;">addLinks</span><span style="color: black;">&#40;</span>result<span style="color: black;">&#91;</span><span style="color: #483d8b;">'links'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">except</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Nao foi possivel obter o link '</span>,link</div></div><p>Super simples. Faço algumas validações básicas e exibo a página atual que o cliente está buscando. Ele basicamente faz os seguintes passos:</p><ol><li>Pega o próximo link à baixar.</li><li>Baixa-o.</li><li>Reporta para o objeto que baixou o link.</li><li>Adiciona mais links na fila de download.</li></ol><p>Eis o sistema acima rodando com dois clientes:</p><div id="attachment_412" class="wp-caption aligncenter" style="width: 310px"><a href="http://herberthamaral.com/wp-content/uploads/2010/05/crawl_distribuido.png"><img class="size-medium wp-image-412" title="crawl_distribuido" src="http://herberthamaral.com/wp-content/uploads/2010/05/crawl_distribuido-300x160.png" alt="" width="300" height="160" /></a><p class="wp-caption-text">Dois clientes rodando paralelamente</p></div><p>Você pode perceber que alguns links podem se repetir. Eu ainda não estudei o PyRO à fundo, mas eu acredito que seja algo relacionado ao tempo sincronização dos objetos dos clientes com o servidor.</p><p>Espero que tenham gostado!</p><p><h4>Posts relacionados:</h4><ol><li><a href='http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i/' rel='bookmark' title='Permanent Link: Criando Web crawlers em Python &#8211; Parte I'>Criando Web crawlers em Python &#8211; Parte I</a></li><li><a href='http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-ii/' rel='bookmark' title='Permanent Link: Criando Web crawlers em Python – Parte II'>Criando Web crawlers em Python – Parte II</a></li><li><a href='http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-iii/' rel='bookmark' title='Permanent Link: Criando Web crawlers em Python &#8211; Parte III'>Criando Web crawlers em Python &#8211; Parte III</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://herberthamaral.com/2010/05/criando-web-crawlers-distribuidos-em-python-parte-iv/feed/</wfw:commentRss> <slash:comments>8</slash:comments> </item> <item><title>Criando Web crawlers em Python &#8211; Parte III</title><link>http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-iii/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=criando-web-crawlers-em-python-parte-iii</link> <comments>http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-iii/#comments</comments> <pubDate>Mon, 22 Mar 2010 16:01:17 +0000</pubDate> <dc:creator>Herberth Amaral</dc:creator> <category><![CDATA[Python]]></category> <category><![CDATA[crawler]]></category><guid isPermaLink="false">http://herberthamaral.com/?p=285</guid> <description><![CDATA[Ir para  Criando Web crawlers em Python &#8211; Parte I Ir para Criando Web crawlers em Python &#8211; Parte II Na parte II desta série de tutoriais, eu mostrei como criar um mini crawler para o SourceForge.net, com suporte à pesquisa e download de softwares. Neste post, eu irei mostrar como gerenciar sessões com o Python [...]]]></description> <content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"> <a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fherberthamaral.com%2F2010%2F03%2Fcriando-web-crawlers-em-python-parte-iii%2F"> <img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fherberthamaral.com%2F2010%2F03%2Fcriando-web-crawlers-em-python-parte-iii%2F&amp;source=HerberthAmaral&amp;style=normal" height="61" width="50" /> </a></div><p>Ir para  <a href="http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i" target="_blank">Criando Web crawlers em Python &#8211; Parte I</a></p><p>Ir para <a href="http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-ii/" target="_blank">Criando Web crawlers em Python &#8211; Parte II</a></p><p>Na <a href="http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-ii/" target="_blank">parte II</a> desta série de tutoriais, eu mostrei como criar um mini crawler para o SourceForge.net, com suporte à pesquisa e download de softwares. Neste post, eu irei mostrar como gerenciar sessões com o Python e um downloader de legendas do <a href="http://legendas.tv">legendas.tv</a> como exemplo de uso.</p><p>Bem, antes de mais nada, o legendas.tv não tem um robots.txt (pelo menos não ao momento que escrevo este post) e como tudo que não é expressamente proibido é permitido, eu posso sem nenhum problema, criar um crawler para baixar legendas de lá. No entanto, eu mandei um email falando sobre a minha experiencia e pedindo permissão. Felizmente, o pessoal do legendas.tv permitiu que eu fizesse o crawler usando-os como cobaias <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p><h3>1 &#8211; Gerenciando sessões no Python.</h3><p>HTTP é um protocolo <em>stateless.</em> Isso quer dizer que ele não guarda o estado da aplicação da mesma forma que um programa que você tem instalado no seu computador faz, por exemplo. Podemos enviar nosso nome de usuário e senhas pro legendas.tv (ou para qualquer outro site). No entanto, há formas de guardar o estado da sua aplicação Web  e uma dessas formas é através de cookies.  O <a href="http://docs.python.org/library/cookielib.html" target="_blank">cookielib</a> do Python faz esse trabalho de gerenciar cookies e faz de uma forma relativamente fácil. Eis um exemplo adaptado da página de documentação do cookielib:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">cookielib</span>, <span style="color: #dc143c;">urllib2</span><br /> cj = <span style="color: #dc143c;">cookielib</span>.<span style="color: black;">CookieJar</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> opener = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">build_opener</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">urllib2</span>.<span style="color: black;">HTTPCookieProcessor</span><span style="color: black;">&#40;</span>cj<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br /> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">install_opener</span><span style="color: black;">&#40;</span>opener<span style="color: black;">&#41;</span><br /> request = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://www.example.com&quot;</span><span style="color: black;">&#41;</span></div></div><p>Apesar do código acima ser um pouco obscuro pra entender, ele basicamente cria um handler (o opener) para lidar com os cookies. A partir daí é só usar o opener para fazer requisições. Podemos enviar nosso nome de usuário e senhas para o portal e automaticamente o opener enviará os cookies comprovando que você está logado. Simples, não? Agora é só enviar nosso usuário e senha para o legendas.tv e sair crawleando:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">cookielib</span>, <span style="color: #dc143c;">urllib2</span>,<span style="color: #dc143c;">urllib</span><br /> <span style="color: #ff7700;font-weight:bold;">from</span> BeautifulSoup <span style="color: #ff7700;font-weight:bold;">import</span> BeautifulSoup<br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span><br /> <br /> base_url = <span style="color: #483d8b;">'http://legendas.tv'</span><br /> cj = <span style="color: #dc143c;">cookielib</span>.<span style="color: black;">CookieJar</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> opener = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">build_opener</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">urllib2</span>.<span style="color: black;">HTTPCookieProcessor</span><span style="color: black;">&#40;</span>cj<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br /> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">install_opener</span><span style="color: black;">&#40;</span>opener<span style="color: black;">&#41;</span><br /> username = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Login: '</span><span style="color: black;">&#41;</span><br /> password = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Senha:'</span><span style="color: black;">&#41;</span><br /> login_data = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'txtLogin'</span>:username,<span style="color: #483d8b;">'txtSenha'</span>:password<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><br /> request = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>base_url+<span style="color: #483d8b;">'/login_verificar.php'</span>,login_data<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">if</span> response.<span style="color: #0000cd;">__contains__</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Dados incorretos'</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Ooops dados incorretos...'</span><br /> &nbsp; &nbsp; <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Pressione uma tecla para sair...'</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <span style="color: #ff7700;font-weight:bold;">else</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Logado com sucesso!'</span></div></div><p>Whoa! Conseguimos logar e estamos prestes a fazer a busca!</p><h3>2 &#8211; Fazendo a busca</h3><p><strong><span style="font-weight: normal;">A busca consiste em três campos:</span></strong></p><p><strong><span style="font-weight: normal;"> </span></strong></p><div id="attachment_293" class="wp-caption aligncenter" style="width: 321px"><a href="http://herberthamaral.com/wp-content/uploads/2010/03/busca1.png"><img class="size-full wp-image-293" title="busca" src="http://herberthamaral.com/wp-content/uploads/2010/03/busca1.png" alt="" width="311" height="159" /></a><p class="wp-caption-text">Campos de busca do legendas.tv</p></div><p><strong><span style="font-weight: normal;"> </span></strong></p><p>Assim como fizemos no login, faremos agora na busca: colocar os dados da busca num dicionário e passar como parâmetro para o urllib2.Request:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">cookielib</span>, <span style="color: #dc143c;">urllib2</span>,<span style="color: #dc143c;">urllib</span><br /> <span style="color: #ff7700;font-weight:bold;">from</span> BeautifulSoup <span style="color: #ff7700;font-weight:bold;">import</span> BeautifulSoup<br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span><br /> <br /> base_url = <span style="color: #483d8b;">'http://legendas.tv'</span><br /> cj = <span style="color: #dc143c;">cookielib</span>.<span style="color: black;">CookieJar</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> opener = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">build_opener</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">urllib2</span>.<span style="color: black;">HTTPCookieProcessor</span><span style="color: black;">&#40;</span>cj<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br /> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">install_opener</span><span style="color: black;">&#40;</span>opener<span style="color: black;">&#41;</span><br /> username = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Login: '</span><span style="color: black;">&#41;</span><br /> password = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Senha:'</span><span style="color: black;">&#41;</span><br /> login_data = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'txtLogin'</span>:username,<span style="color: #483d8b;">'txtSenha'</span>:password<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><br /> request = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>base_url+<span style="color: #483d8b;">'/login_verificar.php'</span>,login_data<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">if</span> response.<span style="color: #0000cd;">__contains__</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Dados incorretos'</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Ooops dados incorretos...'</span><br /> &nbsp; &nbsp; <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Pressione uma tecla para sair...'</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <span style="color: #ff7700;font-weight:bold;">else</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Logado com sucesso!'</span><br /> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Fazendo busca:'</span><br /> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'--------------'</span><br /> <br /> busca = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Buscar por: '</span><span style="color: black;">&#41;</span><br /> tipo = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Tipo:(1 - Release,2 - Filme, 3- Usuário):'</span><span style="color: black;">&#41;</span><br /> idioma = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Idioma: (1 - Português,2 - Ingles,99 - Todos)'</span><span style="color: black;">&#41;</span><br /> <br /> search_dict = <span style="color: black;">&#123;</span><span style="color: #483d8b;">'txtLegenda'</span>:busca,<span style="color: #483d8b;">'selTipo'</span>:tipo,<span style="color: #483d8b;">'int_idioma'</span>:idioma<span style="color: black;">&#125;</span><br /> search_data = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span>search_dict<span style="color: black;">&#41;</span><br /> request = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>base_url+<span style="color: #483d8b;">'/index.php?opcao=buscarlegenda'</span>,search_data<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><br /> page = response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> soup = BeautifulSoup<span style="color: black;">&#40;</span>page<span style="color: black;">&#41;</span></div></div><p>Eu não coloquei todas as opções de idioma para manter o código simples. Só lembrando que esses códigos foram retirados do atributo value dos options do select int_idioma.</p><p>A partir de agora é só brincar um pouco com o <a href="http://www.crummy.com/software/BeautifulSoup/" target="_blank">BeautifulSoup</a> que conseguiremos extrair todos os dados que quisermos. Eis o exemplo:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">span_results = soup.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'td'</span>,<span style="color: black;">&#123;</span><span style="color: #483d8b;">'id'</span>:<span style="color: #483d8b;">'conteudodest'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'span'</span><span style="color: black;">&#41;</span><br /> <br /> i = <span style="color: #ff4500;">0</span><br /> list_download_ids = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br /> <span style="color: #ff7700;font-weight:bold;">for</span> span <span style="color: #ff7700;font-weight:bold;">in</span> span_results:<br /> <br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># há dois tipos de span na busca. Este não contem o que a gente quer</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> span.<span style="color: black;">attrs</span> == <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'class'</span>, <span style="color: #483d8b;">'brls'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">continue</span><br /> <br /> &nbsp; &nbsp; td = span.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'td'</span>,<span style="color: black;">&#123;</span><span style="color: #483d8b;">'class'</span>:<span style="color: #483d8b;">'mais'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#parent encontra o elemento pai. </span><br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#ex: td.parent aponta para tr e tr.parent aponta para table</span><br /> &nbsp; &nbsp; release = td.<span style="color: black;">parent</span>.<span style="color: black;">parent</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'span'</span>,<span style="color: black;">&#123;</span><span style="color: #483d8b;">'class'</span>:<span style="color: #483d8b;">'brls'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br /> <br /> &nbsp; &nbsp; sub_name = td.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; downloads = td.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; comentarios = td.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">7</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; avaliacao = td.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; data = span.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'td'</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#recupera o ID do download que tá no código javascript</span><br /> &nbsp; &nbsp; download_id_js = td.<span style="color: black;">parent</span>.<span style="color: black;">parent</span>.<span style="color: black;">attrs</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; download_id = <span style="color: #dc143c;">re</span>.<span style="color: black;">search</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'[a-z0-9]{32}'</span>,download_id_js<span style="color: black;">&#41;</span>.<span style="color: black;">group</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; list_download_ids.<span style="color: black;">append</span><span style="color: black;">&#40;</span>download_id<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; i+=<span style="color: #ff4500;">1</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Opção: '</span>+<span style="color: #008000;">str</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Serie: '</span>+sub_name<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Release: '</span>+release<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Downloads: '</span>+downloads<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Comentarios: '</span>+comentarios<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Avaliacao: '</span>+avaliacao<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Data: '</span>+data<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'-------------------------------------'</span></div></div><p>A estrutura da página do legendas.tv é um pouco complicada,  por isso nós temos que fazer alguns <em>workarounds</em> (nome bonito para gambiarra) para conseguirmos extrair todos os dados. Um exemplo disso é como eu fiz para pegar o id dentro do código JS inline na página. Isso deixa nosso mini-crawler um pouco mais complexo de entender (de fato é um dos mais complexos que já mexi ate hoje).</p><h3>3 &#8211; O código final</h3><p>Como o legendas.tv não tem link direto para download de legendas e o usuário tem que estar logado para baixa-la, eu preferi não usar o wget para isso, pois iria aumentar a complexidade, já que teríamos que salvar o cookie num arquivo e passar pra ele como parametro para ele baixar a legenda. Então eu preferi deixar tudo com urllib mesmo com alguns tricks com headers. Este é o exemplo final e funcional:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">cookielib</span>, <span style="color: #dc143c;">urllib2</span>,<span style="color: #dc143c;">urllib</span><br /> <span style="color: #ff7700;font-weight:bold;">from</span> BeautifulSoup <span style="color: #ff7700;font-weight:bold;">import</span> BeautifulSoup<br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span><br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span><br /> <br /> base_url = <span style="color: #483d8b;">'http://legendas.tv'</span><br /> cj = <span style="color: #dc143c;">cookielib</span>.<span style="color: black;">CookieJar</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> opener = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">build_opener</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">urllib2</span>.<span style="color: black;">HTTPCookieProcessor</span><span style="color: black;">&#40;</span>cj<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br /> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">install_opener</span><span style="color: black;">&#40;</span>opener<span style="color: black;">&#41;</span><br /> username = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Login: '</span><span style="color: black;">&#41;</span><br /> password = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Senha:'</span><span style="color: black;">&#41;</span><br /> login_data = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'txtLogin'</span>:username,<span style="color: #483d8b;">'txtSenha'</span>:password<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><br /> request = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>base_url+<span style="color: #483d8b;">'/login_verificar.php'</span>,login_data<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">if</span> response.<span style="color: #0000cd;">__contains__</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Dados incorretos'</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Ooops dados incorretos...'</span><br /> &nbsp; &nbsp; <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Pressione uma tecla para sair...'</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <span style="color: #ff7700;font-weight:bold;">else</span>:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Logado com sucesso!'</span><br /> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Fazendo busca:'</span><br /> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'--------------'</span><br /> <br /> busca = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Buscar por: '</span><span style="color: black;">&#41;</span><br /> tipo = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Tipo:(1 - Release,2 - Filme, 3- Usuário):'</span><span style="color: black;">&#41;</span><br /> idioma = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Idioma: (1 - Português,2 - Ingles,99 - Todos)'</span><span style="color: black;">&#41;</span><br /> <br /> search_dict = <span style="color: black;">&#123;</span><span style="color: #483d8b;">'txtLegenda'</span>:busca,<span style="color: #483d8b;">'selTipo'</span>:tipo,<span style="color: #483d8b;">'int_idioma'</span>:idioma<span style="color: black;">&#125;</span><br /> search_data = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span>search_dict<span style="color: black;">&#41;</span><br /> request = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>base_url+<span style="color: #483d8b;">'/index.php?opcao=buscarlegenda'</span>,search_data<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><br /> page = response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> soup = BeautifulSoup<span style="color: black;">&#40;</span>page<span style="color: black;">&#41;</span><br /> <br /> span_results = soup.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'td'</span>,<span style="color: black;">&#123;</span><span style="color: #483d8b;">'id'</span>:<span style="color: #483d8b;">'conteudodest'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'span'</span><span style="color: black;">&#41;</span><br /> <br /> i = <span style="color: #ff4500;">0</span><br /> list_download_ids = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br /> <span style="color: #ff7700;font-weight:bold;">for</span> span <span style="color: #ff7700;font-weight:bold;">in</span> span_results:<br /> <br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># há dois tipos de span na busca. </span><br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#Este não contem o que nós gente queremos</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> span.<span style="color: black;">attrs</span> == <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'class'</span>, <span style="color: #483d8b;">'brls'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>:<br /> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">continue</span><br /> <br /> &nbsp; &nbsp; td = span.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'td'</span>,<span style="color: black;">&#123;</span><span style="color: #483d8b;">'class'</span>:<span style="color: #483d8b;">'mais'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#parent encontra o elemento pai. </span><br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#ex: td.parent aponta para tr e tr.parent aponta para table</span><br /> &nbsp; &nbsp; release = td.<span style="color: black;">parent</span>.<span style="color: black;">parent</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'span'</span>,<span style="color: black;">&#123;</span><span style="color: #483d8b;">'class'</span>:<span style="color: #483d8b;">'brls'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br /> <br /> &nbsp; &nbsp; sub_name = td.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; downloads = td.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">5</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; comentarios = td.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">7</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; avaliacao = td.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; data = span.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'td'</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br /> <br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#recupera o ID do download que tá no código javascript</span><br /> &nbsp; &nbsp; download_id_js = td.<span style="color: black;">parent</span>.<span style="color: black;">parent</span>.<span style="color: black;">attrs</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; download_id = <span style="color: #dc143c;">re</span>.<span style="color: black;">search</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'[a-z0-9]{32}'</span>,download_id_js<span style="color: black;">&#41;</span>.<span style="color: black;">group</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; list_download_ids.<span style="color: black;">append</span><span style="color: black;">&#40;</span>download_id<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; i+=<span style="color: #ff4500;">1</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Opção: '</span>+<span style="color: #008000;">str</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Serie: '</span>+sub_name<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Release: '</span>+release<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Downloads: '</span>+downloads<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Comentarios: '</span>+comentarios<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Avaliacao: '</span>+avaliacao<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Data: '</span>+data<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'-------------------------------------'</span><br /> <br /> download_op = &nbsp;<span style="color: #008000;">int</span><span style="color: black;">&#40;</span><span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Qual opção deseja baixar? '</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br /> url_request = base_url+<span style="color: #483d8b;">'/info.php?d='</span>+list_download_ids<span style="color: black;">&#91;</span>download_op-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>+<span style="color: #483d8b;">'&amp;c=1'</span><br /> request = &nbsp;<span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>url_request<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><br /> legenda = response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #808080; font-style: italic;">#eu acho que todas as legendas estão em formato rar</span><br /> <span style="color: #808080; font-style: italic;">#mas só pro caso de eu estar errado.</span><br /> fname = <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>download_op<span style="color: black;">&#41;</span><br /> <span style="color: #ff7700;font-weight:bold;">if</span> response.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Content-Type'</span><span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__contains__</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'rar'</span><span style="color: black;">&#41;</span>:<br /> &nbsp; &nbsp; fname += <span style="color: #483d8b;">'.rar'</span><br /> <span style="color: #ff7700;font-weight:bold;">else</span>:<br /> &nbsp; &nbsp; fname += <span style="color: #483d8b;">'.zip'</span><br /> f = <span style="color: #008000;">open</span><span style="color: black;">&#40;</span>fname,<span style="color: #483d8b;">'w'</span><span style="color: black;">&#41;</span><br /> f.<span style="color: black;">write</span><span style="color: black;">&#40;</span>legenda<span style="color: black;">&#41;</span><br /> f.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Legenda '</span>+fname+<span style="color: #483d8b;">' salva com sucesso!'</span></div></div><p>Como o intuito desse post é mostrar como poderia ser um crawler para o legendas.tv, eu não me preocupei tanto com a estrutura do script (notem que ele repete algumas coisas algumas vezes) e não me preocupei com validação dos dados.</p><p>No próximo post eu vou dar umas dicas para melhora de performance e escalabilidade do crawler, mas provavelmente demorarei um pouco para escrever (Trabalho de Conclusão de Curso é complicado ..).</p><p>Espero que tenham gostado e gostaria de ouvir de vocês as suas impressões <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> <br /> See ya!</p><p><h4>Posts relacionados:</h4><ol><li><a href='http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-ii/' rel='bookmark' title='Permanent Link: Criando Web crawlers em Python – Parte II'>Criando Web crawlers em Python – Parte II</a></li><li><a href='http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i/' rel='bookmark' title='Permanent Link: Criando Web crawlers em Python &#8211; Parte I'>Criando Web crawlers em Python &#8211; Parte I</a></li><li><a href='http://herberthamaral.com/2010/05/criando-web-crawlers-distribuidos-em-python-parte-iv/' rel='bookmark' title='Permanent Link: Criando Web crawlers (distribuidos) em Python &#8211; Parte IV'>Criando Web crawlers (distribuidos) em Python &#8211; Parte IV</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-iii/feed/</wfw:commentRss> <slash:comments>5</slash:comments> </item> <item><title>Criando Web crawlers em Python – Parte II</title><link>http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-ii/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=criando-web-crawlers-em-python-parte-ii</link> <comments>http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-ii/#comments</comments> <pubDate>Sun, 07 Mar 2010 13:08:50 +0000</pubDate> <dc:creator>Herberth Amaral</dc:creator> <category><![CDATA[Python]]></category> <category><![CDATA[crawler]]></category> <category><![CDATA[tutorial]]></category> <category><![CDATA[web]]></category><guid isPermaLink="false">http://herberthamaral.com/?p=257</guid> <description><![CDATA[Ir para  Criando Web crawlers em Python &#8211; Parte I Ir para Criando Web crawlers em Python &#8211; 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 [...]]]></description> <content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"> <a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fherberthamaral.com%2F2010%2F03%2Fcriando-web-crawlers-em-python-parte-ii%2F"> <img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fherberthamaral.com%2F2010%2F03%2Fcriando-web-crawlers-em-python-parte-ii%2F&amp;source=HerberthAmaral&amp;style=normal" height="61" width="50" /> </a></div><p>Ir para  <a href="http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i" target="_blank">Criando Web crawlers em Python &#8211; Parte I</a></p><p>Ir para <a href="http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-iii/" target="_blank">Criando Web crawlers em Python &#8211; Parte III</a></p><p>No <a href="http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i/" target="_blank">post anterior</a>, eu mostrei como recuperar informações básicas de uma página da Web usando urllib, urllib2 e <a href="http://www.crummy.com/software/BeautifulSoup/" target="_blank">BeautifulSoup</a>. Neste post eu mostrarei como enviar dados via GET e POST.</p><p>Há um excelente guia sobre urllib2: o <a href="http://www.voidspace.org.uk/python/articles/urllib2.shtml" target="_blank">urllib2 &#8211; The Missing Manual</a> 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 <a href="http://sf.net">SourceForge</a> (e da maioria dos outros portais) funcionam.</p><p>Vamos dar uma olhada na URL do na pesquisa por &#8220;Python&#8221; no SF:</p><pre>http://sourceforge.net/search/?type_of_search=soft&amp;words=python</pre><p>Bem, isso indica que temos que enviar duas variáveis para o SF.net: <em>type_of_search</em> (sempre igual à soft) e <em>words</em> (que é a nossa busca). Um exemplo de código que faria essa busca poderia ser esse:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib</span>,<span style="color: #dc143c;">urllib2</span><br /> <br /> base_url = <span style="color: #483d8b;">'http://sourceforge.net'</span><br /> busca = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Pesquisar por: '</span><span style="color: black;">&#41;</span><br /> <br /> variaveis_get = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'type_of_search'</span>:<span style="color: #483d8b;">'soft'</span>,<span style="color: #483d8b;">'words'</span>:busca<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><br /> req = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>base_url+<span style="color: #483d8b;">'/search/'</span>,variaveis_get<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <span style="color: #ff7700;font-weight:bold;">print</span> response</div></div><p>Se der tudo certo, você  deveráver  o código fonte da página do SF que contém os resultados da pesquisa.</p><p>Feito isso, vamos analisar como a marcação do SF é organizada na busca:</p><p style="text-align: center;"><a href="http://herberthamaral.com/wp-content/uploads/2010/03/Screenshot-SourceForge.net-Software-Search-Mozilla-Firefox.png"><img class="aligncenter size-full wp-image-265" title="Resultados da busca no SF.net por Python" src="http://herberthamaral.com/wp-content/uploads/2010/03/Screenshot-SourceForge.net-Software-Search-Mozilla-Firefox.png" alt="" width="994" height="607" /></a></p><p style="text-align: left;">O <a href="http://getfirebug.com/">Firebug</a> 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:</p><ul><li>O resultado da busca está dentro de uma tabela com o id=&#8221;searchtable&#8221;.</li><li>Um resultado da busca está sempre dentro de um td com classe description.</li><li>O nome do projeto está dentro de um link dentro de um h2 dentro desse td &#8220;description&#8221;.</li><li>O link de download se encontra na próxima td da mesma linha da tabela.</li></ul><p><strong>Exibindo as informações dos projetos</strong></p><p>Agora nós temos como buscar nossa informação e como filtra-la. Como disse no<a href="http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i/"> post anterior</a>, 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:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> BeautifulSoup <span style="color: #ff7700;font-weight:bold;">import</span> BeautifulSoup<br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib</span>,<span style="color: #dc143c;">urllib2</span><br /> <br /> base_url = <span style="color: #483d8b;">'http://sourceforge.net'</span><br /> busca = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Pesquisar por: '</span><span style="color: black;">&#41;</span><br /> <br /> variaveis_get = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'type_of_search'</span>:<span style="color: #483d8b;">'soft'</span>,<span style="color: #483d8b;">'words'</span>:busca<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><br /> req = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>base_url+<span style="color: #483d8b;">'/search/'</span>,variaveis_get<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> soup = BeautifulSoup<span style="color: black;">&#40;</span>response<span style="color: black;">&#41;</span><br /> <span style="color: #808080; font-style: italic;"># procura pela tabela com id=searchtable</span><br /> tabela = soup.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'table'</span>,<span style="color: black;">&#123;</span><span style="color: #483d8b;">'id'</span>:<span style="color: #483d8b;">'searchtable'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span> <br /> <span style="color: #808080; font-style: italic;">#retorna uma lista com todas as linhas (&amp;lt;tr&amp;gt;) da tabela</span><br /> linhas_tabela = tabela.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'tr'</span><span style="color: black;">&#41;</span> <br /> <br /> i=<span style="color: #ff4500;">0</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">for</span> linha <span style="color: #ff7700;font-weight:bold;">in</span> linhas_tabela:<br /> &nbsp; &nbsp; i+=<span style="color: #ff4500;">1</span><br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#encontra a primeira coluna (descricao) da linha</span><br /> &nbsp; &nbsp; coluna_descricao = linha.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'td'</span><span style="color: black;">&#41;</span> <br /> <br /> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#o atributo contents contem uma lista com o conteudo da tag</span><br /> &nbsp; &nbsp; nome_projeto = coluna_descricao.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span>.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <br /> <br /> &nbsp; &nbsp; descricao_projeto = coluna_descricao.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Projeto '</span>+<span style="color: #008000;">str</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span>+<span style="color: #483d8b;">': '</span>+nome_projeto<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> descricao_projeto<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'--------------------------------'</span></div></div><p>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 <em>chains</em> (cadeias) de comando como essas:</p><pre class="brush:python">nome_do_primeiro_projeto_da_pesquisa = soup.find('table',{'id':'searchtable'}).findAll('tr')[0].find('td').find('a').contents[0]</pre><p>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&#8230; quem ler seu código assim terá que ter uma boa noção do BeautifulSoup).</p><p><strong>Baixando os arquivos do projeto</strong></p><p>Essa parte é relativamente fácil. O SF é um serviço muito bom, até para o nosso pequeno experimento <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p><p>A URL que o link &#8220;Download Now&#8221; 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 <strong>wget </strong>(um programa bem útil para download de arquivos na Web presente na maioria das distribuições Linux. Um clone para Windows pode ser encontrado <a href="http://gnuwin32.sourceforge.net/packages/wget.htm" target="_blank">aqui</a>) e ele irá baixar o projeto para nós. Simples, não?</p><p>Então vamos ao código:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> BeautifulSoup <span style="color: #ff7700;font-weight:bold;">import</span> BeautifulSoup<br /> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib</span>,<span style="color: #dc143c;">urllib2</span><br /> <span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">subprocess</span> <span style="color: #ff7700;font-weight:bold;">import</span> call<br /> <br /> base_url = <span style="color: #483d8b;">'http://sourceforge.net'</span><br /> busca = <span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Pesquisar por: '</span><span style="color: black;">&#41;</span><br /> <br /> variaveis_get = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'type_of_search'</span>:<span style="color: #483d8b;">'soft'</span>,<span style="color: #483d8b;">'words'</span>:busca<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><br /> req = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>base_url+<span style="color: #483d8b;">'/search/'</span>,variaveis_get<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> soup = BeautifulSoup<span style="color: black;">&#40;</span>response<span style="color: black;">&#41;</span><br /> <br /> <span style="color: #808080; font-style: italic;"># procura pela tabela com id=searchtable</span><br /> tabela = soup.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'table'</span>,<span style="color: black;">&#123;</span><span style="color: #483d8b;">'id'</span>:<span style="color: #483d8b;">'searchtable'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span> <br /> <br /> &nbsp;<span style="color: #808080; font-style: italic;">#retorna uma lista com todas as linhas da tabela</span><br /> linhas_tabela = tabela.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'tr'</span><span style="color: black;">&#41;</span><br /> <br /> i=<span style="color: #ff4500;">0</span><br /> links_download = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">for</span> linha <span style="color: #ff7700;font-weight:bold;">in</span> linhas_tabela:<br /> &nbsp; &nbsp; i+=<span style="color: #ff4500;">1</span><br /> &nbsp; &nbsp; coluna_descricao = linha.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'td'</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; nome_projeto = coluna_descricao.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span>.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; link_download = linha.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span>,<span style="color: black;">&#123;</span><span style="color: #483d8b;">'class'</span>:<span style="color: #483d8b;">'downloadnow'</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'href'</span><span style="color: black;">&#93;</span><br /> &nbsp; &nbsp; links_download.<span style="color: black;">append</span><span style="color: black;">&#40;</span>link_download<span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; descricao_projeto = coluna_descricao.<span style="color: black;">contents</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Projeto '</span>+<span style="color: #008000;">str</span><span style="color: black;">&#40;</span>i<span style="color: black;">&#41;</span>+<span style="color: #483d8b;">': '</span>+nome_projeto<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> descricao_projeto<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'--------------------------------'</span><br /> <br /> opcao = <span style="color: #008000;">int</span><span style="color: black;">&#40;</span><span style="color: #008000;">raw_input</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Qual projeto gostaria de baixar? '</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br /> opcao_url = base_url+links_download<span style="color: black;">&#91;</span>opcao-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><br /> call<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'wget'</span>,opcao_url<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;">#chama o wget com o link para download</span></div></div><p>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 <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p><p>No proximo post eu mostrarei como guardar valores de sessão para percorrermos páginas protegidas por senha. See ya!</p><p><h4>Posts relacionados:</h4><ol><li><a href='http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i/' rel='bookmark' title='Permanent Link: Criando Web crawlers em Python &#8211; Parte I'>Criando Web crawlers em Python &#8211; Parte I</a></li><li><a href='http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-iii/' rel='bookmark' title='Permanent Link: Criando Web crawlers em Python &#8211; Parte III'>Criando Web crawlers em Python &#8211; Parte III</a></li><li><a href='http://herberthamaral.com/2010/05/criando-web-crawlers-distribuidos-em-python-parte-iv/' rel='bookmark' title='Permanent Link: Criando Web crawlers (distribuidos) em Python &#8211; Parte IV'>Criando Web crawlers (distribuidos) em Python &#8211; Parte IV</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-ii/feed/</wfw:commentRss> <slash:comments>9</slash:comments> </item> <item><title>Criando Web crawlers em Python &#8211; Parte I</title><link>http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=criando-web-crawlers-em-python-parte-i</link> <comments>http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i/#comments</comments> <pubDate>Sat, 27 Feb 2010 22:58:17 +0000</pubDate> <dc:creator>Herberth Amaral</dc:creator> <category><![CDATA[Python]]></category> <category><![CDATA[crawler]]></category> <category><![CDATA[web]]></category><guid isPermaLink="false">http://herberthamaral.com/?p=242</guid> <description><![CDATA[Ir para: Criando Web Crawlers em Python &#8211; Parte II Ir para: Criando Web Crawlers em Python &#8211; Parte III 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 [...]]]></description> <content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"> <a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fherberthamaral.com%2F2010%2F02%2Fcriando-web-crawlers-em-python-parte-i%2F"> <img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fherberthamaral.com%2F2010%2F02%2Fcriando-web-crawlers-em-python-parte-i%2F&amp;source=HerberthAmaral&amp;style=normal" height="61" width="50" /> </a></div><p><strong>Ir para: </strong><a href="http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-ii/" target="_blank"><strong>Criando Web Crawlers em Python &#8211; Parte II</strong></a></p><p><strong>Ir para: </strong><a href="http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-iiI/" target="_blank"><strong>Criando Web Crawlers em Python &#8211; Parte III</strong></a></p><p>Iniciemos com a definição de Web crawler:</p><blockquote><p>Um Web crawler é um programa de computador que navega pela World Wide Web de maneira metódica e automatizada. [Wikipedia]</p></blockquote><p>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.</p><p>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).</p><p><strong>Aspectos legais e ética de crawlers</strong>:</p><p>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.</p><p><strong>O processo:</strong></p><div id="attachment_245" class="wp-caption aligncenter" style="width: 310px"><a href="http://herberthamaral.com/wp-content/uploads/2010/02/crawler.png"><img class="size-medium wp-image-245" title="Crawler" src="http://herberthamaral.com/wp-content/uploads/2010/02/crawler-300x290.png" alt="Esquema básico de funcionamento de um Web Crawler" width="300" height="290" /></a><p class="wp-caption-text">Esquema básico de funcionamento de um Web Crawler</p></div><p>Preste atenção aos componentes do crawler:</p><ol><li>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.</li><li>Downloader: geralmente costuma-se colocar um downloader multithreaded. No nosso primero exemplo vamos fazer um downloader singlethreaded para evitar complexidade.</li><li>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.</li><li>Storage: pode ser qualquer tipo de armazenamento em qualquer tipo de mídia. Não iremos persistir os dados nessa primeira parte do tutorial.</li></ol><p>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.</p><p><strong>Maos à obra: fazendo um downloader com uma fila simples</strong></p><p>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:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span><br /> <br /> url = <span style="color: #483d8b;">&quot;http://www.google.com&quot;</span><br /> <br /> request = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><br /> document = response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <span style="color: #ff7700;font-weight:bold;">print</span> document</div></div><p>Execute esse código e se tudo der certo você verá o código fonte da página inicial do Google!</p><p>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.</p><p>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 <strong>BeautifulSoup</strong>. 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.</p><p>Façamos algo útil: vamos listar todos os links da página inicial do Google.</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span><br /> <span style="color: #ff7700;font-weight:bold;">from</span> BeautifulSoup <span style="color: #ff7700;font-weight:bold;">import</span> BeautifulSoup<br /> <br /> url = <span style="color: #483d8b;">&quot;http://www.google.com&quot;</span><br /> <br /> request = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><br /> document = response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #808080; font-style: italic;">#normaliza o documento para que o mesmo seja acessível via objetos</span><br /> soup = BeautifulSoup<span style="color: black;">&#40;</span>document<span style="color: black;">&#41;</span> <br /> <br /> <span style="color: #808080; font-style: italic;"># retorna uma lista com todos os links do documento</span><br /> links = soup.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span> &nbsp;<br /> <br /> <span style="color: #ff7700;font-weight:bold;">for</span> link <span style="color: #ff7700;font-weight:bold;">in</span> links:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> link</div></div><p>Fácil não?!</p><p>Se tudo correr bem, você deve ver uma saída igual a essa:</p><pre style="color: #bbb;">
<div id="_mcePaste">&lt;a href="http://images.google.com.br/imghp?hl=pt-BR&amp;amp;tab=wi"&gt;Imagens&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="http://video.google.com.br/?hl=pt-BR&amp;amp;tab=wv"&gt;Vídeos&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="http://maps.google.com.br/maps?hl=pt-BR&amp;amp;tab=wl"&gt;Mapas&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="http://news.google.com.br/nwshp?hl=pt-BR&amp;amp;tab=wn"&gt;Notícias&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="http://www.orkut.com/Home.aspx?hl=pt-BR&amp;amp;tab=w0"&gt;Orkut&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="http://mail.google.com/mail/?hl=pt-BR&amp;amp;tab=wm"&gt;Gmail&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="http://www.google.com.br/intl/pt-BR/options/" style="text-decoration:none"&gt;&lt;u&gt;mais&lt;/u&gt; &amp;raquo;&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="/url?sa=p&amp;amp;pref=ig&amp;amp;pval=3&amp;amp;q=http://www.google.com.br/ig%3Fhl%3Dpt-BR%26source%3Diglk&amp;amp;usg=AFQjCNEufhwNAC9POZqcS5r7r07CUPbvAA"&gt;iGoogle&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="/preferences?hl=pt-BR"&gt;Configurações da pesquisa&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="https://www.google.com/accounts/Login?hl=pt-BR&amp;amp;continue=http://www.google.com.br/"&gt;Fazer login&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="/search?q=Vancouver+2010&amp;amp;ct=olympics10-sskating-hp&amp;amp;oi=ddle"&gt;&lt;img src="/logos/olympics10-sskating-hp.png" width="523" height="170" border="0" alt="Vancouver 2010" title="Vancouver 2010" id="logo" onload="window.lol&amp;amp;&amp;amp;lol()" /&gt;&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="/advanced_search?hl=pt-BR"&gt;Pesquisa avançada&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="/language_tools?hl=pt-BR"&gt;Ferramentas de idiomas&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="/intl/pt-BR/ads/"&gt;Soluções de publicidade&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="/services/"&gt;Soluções empresariais&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="/intl/pt-BR/about.html"&gt;Tudo sobre o Google&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="http://www.google.com/ncr"&gt;Google.com in English&lt;/a&gt;</div>
<div id="_mcePaste">&lt;a href="/intl/pt-BR/privacy.html"&gt;Privacidade&lt;/a&gt;</div>

&lt;a href="http://images.google.com.br/imghp?hl=pt-BR&amp;amp;tab=wi"&gt;Imagens&lt;/a&gt;&lt;a href="http://video.google.com.br/?hl=pt-BR&amp;amp;tab=wv"&gt;Vídeos&lt;/a&gt;&lt;a href="http://maps.google.com.br/maps?hl=pt-BR&amp;amp;tab=wl"&gt;Mapas&lt;/a&gt;&lt;a href="http://news.google.com.br/nwshp?hl=pt-BR&amp;amp;tab=wn"&gt;Notícias&lt;/a&gt;&lt;a href="http://www.orkut.com/Home.aspx?hl=pt-BR&amp;amp;tab=w0"&gt;Orkut&lt;/a&gt;&lt;a href="http://mail.google.com/mail/?hl=pt-BR&amp;amp;tab=wm"&gt;Gmail&lt;/a&gt;&lt;a href="http://www.google.com.br/intl/pt-BR/options/" style="text-decoration:none"&gt;&lt;u&gt;mais&lt;/u&gt; &amp;raquo;&lt;/a&gt;&lt;a href="/url?sa=p&amp;amp;pref=ig&amp;amp;pval=3&amp;amp;q=http://www.google.com.br/ig%3Fhl%3Dpt-BR%26source%3Diglk&amp;amp;usg=AFQjCNEufhwNAC9POZqcS5r7r07CUPbvAA"&gt;iGoogle&lt;/a&gt;&lt;a href="/preferences?hl=pt-BR"&gt;Configurações da pesquisa&lt;/a&gt;&lt;a href="https://www.google.com/accounts/Login?hl=pt-BR&amp;amp;continue=http://www.google.com.br/"&gt;Fazer login&lt;/a&gt;&lt;a href="/search?q=Vancouver+2010&amp;amp;ct=olympics10-sskating-hp&amp;amp;oi=ddle"&gt;&lt;img src="/logos/olympics10-sskating-hp.png" width="523" height="170" border="0" alt="Vancouver 2010" title="Vancouver 2010" id="logo" onload="window.lol&amp;amp;&amp;amp;lol()" /&gt;&lt;/a&gt;&lt;a href="/advanced_search?hl=pt-BR"&gt;Pesquisa avançada&lt;/a&gt;&lt;a href="/language_tools?hl=pt-BR"&gt;Ferramentas de idiomas&lt;/a&gt;&lt;a href="/intl/pt-BR/ads/"&gt;Soluções de publicidade&lt;/a&gt;&lt;a href="/services/"&gt;Soluções empresariais&lt;/a&gt;&lt;a href="/intl/pt-BR/about.html"&gt;Tudo sobre o Google&lt;/a&gt;&lt;a href="http://www.google.com/ncr"&gt;Google.com in English&lt;/a&gt;&lt;a href="/intl/pt-BR/privacy.html"&gt;Privacidade&lt;/a&gt;</pre><p>Na verdade, a linha</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">links = soup.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span></div></div><p>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:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span><br /> <span style="color: #ff7700;font-weight:bold;">from</span> BeautifulSoup <span style="color: #ff7700;font-weight:bold;">import</span> BeautifulSoup<br /> <br /> url = <span style="color: #483d8b;">&quot;http://www.google.com&quot;</span><br /> <br /> request = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span><br /> response = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><br /> document = response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> <br /> <span style="color: #808080; font-style: italic;">#normaliza o documento para que o mesmo seja acessível via objetos</span><br /> soup = BeautifulSoup<span style="color: black;">&#40;</span>document<span style="color: black;">&#41;</span> <br /> <br /> <span style="color: #808080; font-style: italic;"># retorna uma lista com todos os links do documento</span><br /> links = soup.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span> &nbsp;<br /> <br /> <span style="color: #ff7700;font-weight:bold;">for</span> link <span style="color: #ff7700;font-weight:bold;">in</span> links:<br /> &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> link<span style="color: black;">&#91;</span><span style="color: #483d8b;">'href'</span><span style="color: black;">&#93;</span></div></div><p>Como saída, você pode obter algo do tipo:</p><pre style="color: #bbb;">http://images.google.com.br/imghp?hl=pt-BR&amp;tab=wi

http://video.google.com.br/?hl=pt-BR&amp;tab=wv


http://maps.google.com.br/maps?hl=pt-BR&amp;tab=wl


http://news.google.com.br/nwshp?hl=pt-BR&amp;tab=wn


http://www.orkut.com/Home.aspx?hl=pt-BR&amp;tab=w0


http://mail.google.com/mail/?hl=pt-BR&amp;tab=wm


http://www.google.com.br/intl/pt-BR/options/

/url?sa=p&amp;pref=ig&amp;pval=3&amp;q=http://www.google.com.br/ig%3Fhl%3Dpt-BR%26source%3Diglk&amp;usg=AFQjCNEufhwNAC9POZqcS5r7r07CUPbvAA
/preferences?hl=pt-BR

https://www.google.com/accounts/Login?hl=pt-BR&amp;continue=http://www.google.com.br/

/search?q=Vancouver+2010&amp;ct=olympics10-sskating-hp&amp;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</pre><p>Como você pode ver, o BeautifulSoup é quase uma mãe quando o assunto é extrair informações de HTML <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> .</p><p>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!</p><p><h4>Posts relacionados:</h4><ol><li><a href='http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-ii/' rel='bookmark' title='Permanent Link: Criando Web crawlers em Python – Parte II'>Criando Web crawlers em Python – Parte II</a></li><li><a href='http://herberthamaral.com/2010/03/criando-web-crawlers-em-python-parte-iii/' rel='bookmark' title='Permanent Link: Criando Web crawlers em Python &#8211; Parte III'>Criando Web crawlers em Python &#8211; Parte III</a></li><li><a href='http://herberthamaral.com/2010/05/criando-web-crawlers-distribuidos-em-python-parte-iv/' rel='bookmark' title='Permanent Link: Criando Web crawlers (distribuidos) em Python &#8211; Parte IV'>Criando Web crawlers (distribuidos) em Python &#8211; Parte IV</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://herberthamaral.com/2010/02/criando-web-crawlers-em-python-parte-i/feed/</wfw:commentRss> <slash:comments>12</slash:comments> </item> <item><title>Python e computacao cientifica</title><link>http://herberthamaral.com/2009/11/python-e-computacao-cientifica/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=python-e-computacao-cientifica</link> <comments>http://herberthamaral.com/2009/11/python-e-computacao-cientifica/#comments</comments> <pubDate>Mon, 30 Nov 2009 00:28:34 +0000</pubDate> <dc:creator>Herberth Amaral</dc:creator> <category><![CDATA[Python]]></category> <category><![CDATA[computação científica]]></category><guid isPermaLink="false">http://herberthamaral.com/?p=24</guid> <description><![CDATA[Há algum tempo eu venho notando algumas aplicações desenvolvidas em Python e desde então eu venho me perguntando: será mesmo possível utilizar Python, de forma eficiente, no meio científico? Bem, minha pesquisa me leva a crer que sim, absolutamente. O Guido Van Rossum, criador e atual mantenedor da linguagem, postou recentemente em seu blog sobre a [...]]]></description> <content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"> <a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fherberthamaral.com%2F2009%2F11%2Fpython-e-computacao-cientifica%2F"> <img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fherberthamaral.com%2F2009%2F11%2Fpython-e-computacao-cientifica%2F&amp;source=HerberthAmaral&amp;style=normal" height="61" width="50" /> </a></div><p>Há algum tempo eu venho notando algumas aplicações desenvolvidas em Python e desde então eu venho me perguntando: será mesmo possível utilizar Python, de forma eficiente, no meio científico? Bem, minha pesquisa me leva a crer que sim, absolutamente.</p><p>O <a href="http://en.wikipedia.org/wiki/Guido_van_Rossum" target="_blank">Guido Van Rossum</a>, criador e atual mantenedor da linguagem, <a href="http://neopythonic.blogspot.com/2009/11/python-in-scientific-world.html">postou recentemente</a> em seu <a href="http://neopythonic.blogspot.com/" target="_blank">blog</a> sobre a <a href="http://ipython.scipy.org/moin/Py4Science">Py4Science</a>, um workshop que visou demonstrar como o Python está sendo útil na prática em pesquisas científicas.</p><p>Eu sabia que Python era perfeitamente aplicável à pesquisas científicas, seja pelo poder da linguagem ou pelas bibliotecas e frameworks que ela provê para facilitar o desenvolvimento de aplicações científicas, mais notavelmente o <a href="http://www.scipy.org/">SciPy</a>, <a href="http://www.numpy.org/">NumPy</a> e o <a href="http://matplotlib.sourceforge.net/" target="_blank">MatPlotLib</a>. O me impressionou foi ver o nível dos projetos envolvidos:</p><ul><li>O time do Telescópio Hubble <a href="http://www.spacetelescope.org/about/further_information/newsletters/pdf/newsletter_40.pdf">utiliza Python</a> há mais de 10 anos</li><li>O pessoal da Universidade de Washington está trabalhando no <a href="http://www.sagemath.org/">SAGE</a>, um software com o objetivo de servir de alternativa viável ao Matlab, Mathematica, Maple e Magma.</li><li><a href="http://nipy.sourceforge.net/nipype/" target="_blank">Nipype</a>, software para criação de interfaces de softwares de neuroimagem.</li><li><a href="http://live.sympy.org" target="_blank">SymPy</a>, biblioteca para matemática simbólica, escrita em Python puro.</li><li>Um projeto de $1 bilhão do governo indiano para melhorar a educação na Índia. Inclui o Departamento de Engenharia Aeroespacial em IIT Bombay na educação de Ciência e Engenharia. Mais em <a href="http://fossee.in/">http://fossee.in/</a></li><li><a href="http://biopython.org/wiki/Main_Page" target="_blank">Biopython</a>, conjunto de ferramentas para computação biológica.</li><li><a href="http://pypi.python.org/pypi?:action=browse&amp;c=385" target="_blank">Vários outros.</a></li></ul><p>Recentemente, eu vi <a href="http://groups.google.it/group/scipy-user/browse_thread/thread/0eb1517095963c9a#  " target="_blank">uma discussão no Google Groups</a> em que o autor pergunta por que o SciPy é melhor que o Matlab. Tá certo que uma pergunta dessas é bem tendenciosa (um amigo <a href="http://twitter.com/stevelacerda/status/6142550364" target="_self">disse</a> que aconteceria o mesmo na lista do Matlab), mas eu li toda a discussão e vi coisas bastante interessante, principalmente quando dizem sobre o <a href="http://cens.ioc.ee/projects/f2py2e/">f2py</a>. Para quem tem código legado em Fortran, quer mudar e tá com qualquer dificuldade, essa é uma ótima oportunidade.</p><p>Algo que eu não posso deixar de falar é da <a href="http://conference.scipy.org/">Python in Science Conference (SciPy Conference)</a>, uma super conferência anual sobre SciPy e Python em computação científica que acontece no Caltech, Califórnia. Ainda não vi nenhum trabalho brasileiro lá. Já é hora, hein?</p><p>Eu sou longe de ser um cientista de renome para falar como o Python tem me ajudado em minhas pesquisas científicas. Mas, como acadêmico, eu posso dizer que serve perfeitamente para meus trabalhos universitários e eu percebo que a vida para outros acadêmicos poderia ser mais simples se eles utilizassem Python. Somente o fato de não precisar lidar com ponteiros ou gerenciamentos de baixo nível atrai algumas pessoas. Outra coisa importante: Python é livre e gratuito. Você não precisa piratear ou comprar uma cópia cara como algumas pessoas fazem com o Matlab e outros softwares <img src='http://herberthamaral.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /></p><p>Links úteis:</p><ul><li><a href="http://" target="_blank">http://groups.google.it/group/scipy-user/browse_thread/thread/0eb1517095963c9a#</a></li><li><a href="http://fperez.org/py4science/index.html  " target="_blank">http://fperez.org/py4science/index.html</a></li><li><a href="http://www.scipy.org" target="_blank">http://www.scipy.org</a></li><li><a href="http://conference.scipy.org/" target="_blank">http://conference.scipy.org/</a></li><li><a href="http://neopythonic.blogspot.com" target="_blank">http://neopythonic.blogspot.com</a></li></ul><p>==EDIT==</p><p>Por algum motivo ainda desconhecido, o título não está aparecendo com os devidos acentos. Irei alterar quando eu souber o que está acontecendo.</p><p>Sem posts relacionados.</p>]]></content:encoded> <wfw:commentRss>http://herberthamaral.com/2009/11/python-e-computacao-cientifica/feed/</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Hello World de Python + OpenGL</title><link>http://herberthamaral.com/2009/11/hello-world-de-python-opengl/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=hello-world-de-python-opengl</link> <comments>http://herberthamaral.com/2009/11/hello-world-de-python-opengl/#comments</comments> <pubDate>Wed, 25 Nov 2009 02:51:32 +0000</pubDate> <dc:creator>Herberth Amaral</dc:creator> <category><![CDATA[Python]]></category> <category><![CDATA[hello world]]></category> <category><![CDATA[opengl]]></category> <category><![CDATA[unimontes]]></category><guid isPermaLink="false">http://herberthamaral.com/?p=10</guid> <description><![CDATA[Há quase um ano eu comecei a estudar Python e gostei de muitas características da linguagem, como o fato de ser de altíssimo nível (very high level), sintaxe clara e elegante, poderosa, portável,  super rápida,fácil aprendizado e um dos melhores: tipagem forte e dinâmica. Gostei tanto que comecei a fazer alguns trabalhos de faculdade (mais [...]]]></description> <content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"> <a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fherberthamaral.com%2F2009%2F11%2Fhello-world-de-python-opengl%2F"> <img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fherberthamaral.com%2F2009%2F11%2Fhello-world-de-python-opengl%2F&amp;source=HerberthAmaral&amp;style=normal" height="61" width="50" /> </a></div><p>Há quase um ano eu comecei a estudar <a title="Python" href="http://www.python.org" target="_blank">Python </a>e gostei de muitas características da linguagem, como o fato de ser de altíssimo nível (<em>very high level</em>), sintaxe clara e elegante, poderosa, portável,  super rápida,fácil aprendizado e um dos melhores: tipagem forte e dinâmica.</p><p>Gostei tanto que comecei a fazer alguns trabalhos de faculdade (mais notavelmente trabalhos nas áreas de Banco de Dados, Inteligência Artificial e, recentemente, Computação Gráfica) usando Python. Para vários trabalhos eu encontrei <em>snippets </em> de código, mas não foi tão fácil para CG usando OpenGL. Por isso, resolvi postar esse pequeno exemplo de como usar Python (na versão 2.6.4) + OpenGL.</p><p>Primeiro, baixe o PyOpenGL em <a href="http://pypi.python.org/pypi/PyOpenGL">http://pypi.python.org/pypi/PyOpenGL</a>, descompacte e execute os comandos para instalar o pacote:´</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$python setup.py build<br /> $sudo python setup.py install</div></div><p>Lembrando que se você estiver no Windows, o executável do Python deverá estar no seu PATH.</p><p>Instalado o pacote, é hora de fazer um teste. Abra o shell do Python e digite isso:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">import</span> OpenGL</div></div><p>Se não aparecer nenhuma mensagem de erro, o pacote do OpenGL foi instalado com sucesso. Agora é hora de uma pequena demonstração de uso do PyOpenGL:</p><div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">from</span> OpenGL.<span style="color: #dc143c;">GL</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br /> <span style="color: #ff7700;font-weight:bold;">from</span> OpenGL.<span style="color: black;">GLUT</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span><br /> <br /> <span style="color: #ff7700;font-weight:bold;">def</span> display<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br /> &nbsp; glClear <span style="color: black;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: black;">&#41;</span><br /> &nbsp; glBegin <span style="color: black;">&#40;</span>GL_POLYGON<span style="color: black;">&#41;</span><br /> &nbsp; glVertex2f<span style="color: black;">&#40;</span><span style="color: #ff4500;">0.4</span>,<span style="color: #ff4500;">0.4</span><span style="color: black;">&#41;</span><br /> &nbsp; glVertex2f<span style="color: black;">&#40;</span><span style="color: #ff4500;">0.01</span>,<span style="color: #ff4500;">0.01</span><span style="color: black;">&#41;</span><br /> &nbsp; glVertex2f<span style="color: black;">&#40;</span><span style="color: #ff4500;">0.3</span>,<span style="color: #ff4500;">0.6</span><span style="color: black;">&#41;</span><br /> &nbsp; glEnd<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> &nbsp; glFlush<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> glutInit <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br /> glutInitDisplayMode <span style="color: black;">&#40;</span>GLUT_SINGLE | GLUT_RGB<span style="color: black;">&#41;</span><br /> glutInitWindowSize <span style="color: black;">&#40;</span><span style="color: #ff4500;">250</span>,<span style="color: #ff4500;">250</span><span style="color: black;">&#41;</span><br /> glutInitWindowPosition <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><br /> glutCreateWindow <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Testando o PyGraphs&quot;</span><span style="color: black;">&#41;</span><br /> glClearColor <span style="color: black;">&#40;</span><span style="color: #ff4500;">0.0</span>, <span style="color: #ff4500;">0.0</span>, <span style="color: #ff4500;">0.0</span>, <span style="color: #ff4500;">0.0</span><span style="color: black;">&#41;</span><br /> glOrtho <span style="color: black;">&#40;</span><span style="color: #ff4500;">0.0</span>, <span style="color: #ff4500;">1.0</span>, <span style="color: #ff4500;">0.0</span>, <span style="color: #ff4500;">1.0</span>, -<span style="color: #ff4500;">1.0</span>, <span style="color: #ff4500;">1.0</span><span style="color: black;">&#41;</span><br /> glutDisplayFunc<span style="color: black;">&#40;</span>display<span style="color: black;">&#41;</span><br /> glutMainLoop <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></div><p>A API do OpenGL pro Python segue as mesmas convenções da API para C/C++. Então, todo e qualquer exemplo que você achar na Web em C/C++ é compatível com o Python (as vezes com algumas pequenas alterações de tipos, mas o nome das funções continua o mesmo).</p><p>Se tudo estiver ok, você deverá ver algo parecido com a seguinte figura:</p><p><img class="alignnone size-full wp-image-16" title="pygraph" src="http://herberthamaral.com/wp-content/uploads/2009/11/pygraph.png" alt="pygraph" width="267" height="289" /></p><p>Alguns links úteis:</p><ul><li><a href="http://www.opengl.org/sdk/docs/man/">http://www.opengl.org/sdk/docs/man/</a></li><li><a href="http://www.inf.pucrs.br/~manssour/OpenGL" target="_blank">www.inf.pucrs.br/~manssour/OpenGL</a></li><li><a href="http://nehe.gamedev.net" target="_blank">nehe.gamedev.net</a></li></ul><p>Acho que é isso. Até a próxima!</p><p>Sem posts relacionados.</p>]]></content:encoded> <wfw:commentRss>http://herberthamaral.com/2009/11/hello-world-de-python-opengl/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> </channel> </rss>