Como criar um executável com Instalador MSI em Python

Esse post é o primeiro da série Distribuir Programas em Python para Desktops Windows. Esse é o mais básico de todos, e esse assunto já foi bem discutido em diversos sites, mas a minha ideia aqui é apresentar como criei o programa de exemplo, mostrar como posso gerar um instalador bem simples já com as bibliotecas que o programa precisa pra rodar em outros Windows.

Toda vez que você gera um executável em Python, o windows precisa das DLLs de Runtime do C++, o tal do Microsoft Visual C++ Redistributable, você vai encontrar como MSVCR. A versão que será necessária depende de qual versão do Python você está usando.

Nós temos três coisas a fazer:

  1. Criar o script do programa
  2. Criar um arquivo de setup para gerar o executável.
  3. Gerar o Instalador MSI

Vou criar um script besta em python só pra ilustrar esses posts, isso é de uma brincadeira idiota que fiz com um amigo meu. Toda vez que o usuário apertar Print Screen o aplicativo vai abrir uma foto de uma boneca, como da foto abaixo:

baby-looking-like-his-doll

 


#boneca.py
import os
import sys
import ctypes
from ctypes import wintypes
import win32con

byref = ctypes.byref
user32 = ctypes.windll.user32

HOTKEYS = {
    1 : (win32con.VK_SNAPSHOT, 0), ####Essa Linha Pega a tecla "PRINT SCREEN"
    2 : (win32con.VK_F4, win32con.MOD_WIN)
}

def handle_win_f3 ():
    os.startfile(os.path.join(os.path.realpath(os.path.dirname(sys.argv[0])),"boneca.jpg"))

def handle_win_f4 ():
    user32.PostQuitMessage (0)

HOTKEY_ACTIONS = {
    1 : handle_win_f3,
    2 : handle_win_f4
}


# Registrando as chaves sem dar o print pra ficar escondido na tela.
for id, (vk, modifiers) in HOTKEYS.items ():
    #print "Registering id", id, "for key", vk
    pass
    if not user32.RegisterHotKey (None, id, modifiers, vk):
        #print "Unable to register id", id
        pass


# Executando as funções e tirando o registro das chaves depois do encerramento do programa.
try:
    msg = wintypes.MSG ()
    while user32.GetMessageA (byref (msg), None, 0, 0) != 0:
        if msg.message == win32con.WM_HOTKEY:
            action_to_take = HOTKEY_ACTIONS.get (msg.wParam)
            if action_to_take:
                action_to_take ()

        user32.TranslateMessage (byref (msg))
        user32.DispatchMessageA (byref (msg))

finally:
    for id in HOTKEYS.keys ():
        user32.UnregisterHotKey (None, id)

Como referência pra esse código eu usei o post do Tim Golden[1].

O código é simples, ele cria dois atalhos no windows, um é o Print Screen que quando pressionado roda a função handle_win_f3 que faz a chamada da foto da boneca.jpg

Já quando ele pressionar o atalho Win + F4 será executada a função handle_win_f4 que apenas encerra o programa. Ele não tem interface gráfica, o que faz sentido pra essa brincadeira.

Beleza, até aí só um script python fácil, agora nós precisamos fazer o Frozen dessa aplicação. Gerar um Frozen (um módulo congelado) é compilar o script e gerar um executável que contenha o interpretador python, suas bibliotecas, seu script e seus arquivos tudo em um lugar só e com um executável (ou mais executáveis). Para isso você precisa criar um arquivo de setup e escolher uma ferramenta para fazer o frozen, os mais usados são py2exe, py2app, cx_freeze, e o pyinstaller. Nesse caso eu vou usar o cx_freeze. Esse arquivo por convenção é chamado de setup.py e


#setup.py
from cx_Freeze import setup, Executable

setup(
    name = "boneca",
    version = "1.0.0",
    options = {"build_exe": {
        'packages': ["os","sys","ctypes","win32con"],
        'include_files': ['boneca.jpg'],
        'include_msvcr': True,
    }},
    executables = [Executable("boneca.py",base="Win32GUI")]
    )

O script também é simples, ele segue a mesma lógica do disutils , só quero chamar atenção para o include_msvcr que vai colocar as DLLs do Microsoft Visual C++ Redistributable no seu executável, dessa forma ele vai copiar as DLLs que já existem no seu sistema operacional. Esse é o único jeito do seu programa funcionar em outros windows, pois o Python precisa dessas dlls para ser executado. Você também pode baixar o próprio instalador do MSVCR da Microsoft e incorporar no seu instalador usando o Inno Setup, por exemplo, vou mostrar isso em um dos próximos posts da série.

Agora vamos gerar um MSI, ou seja, um instalador para windows. Só rodar na linha de comando:

python setup.py bdist_msi

Beleza, agora ele criou uma pasta chamada dist com um arquivo boneca-1.0.0-win32.msi (ou boneca-1.0.0-amd64.msi se seu sistema for 64) agora já dá pra instalar e usar. Então aqui mostrei Como criar um executável com Instalador MSI em Python e com Cx_freeze.

Os scripts estão no meu Github: https://github.com/ffreitasalves/boneca

[1]: http://timgolden.me.uk/python/win32_how_do_i/catch_system_wide_hotkeys.html

Distribuir Programas em Python para Desktops Windows

Comecei a escrever um post sobre como criar um programa com auto-update em Python e como vi que tinha muito assunto pra falar eu resolvi escrever 3 posts, em cada um vou tratar de um assunto mas o objetivo final é conseguir criar um executável em Python com auto-update e que tenha um instalador.

Então os posts estão divididos em 3 partes:

  1. Como criar um executável com Instalador MSI com Python e Cx_freeze
  2. Como criar um programa com Auto-Update utilizando Python e Esky
  3. Como criar um instalador MSI utilizando o Inno Setup

Durante esses 3 posts vou criar um programa bem simples (chamado boneca), mostrar como eu posso criar o instalador pelo próprio Cx_freeze, depois mostrar como posso criar o auto-update utilizando o Esky e por fim mostrar como posso usar o Inno Setup pra criar um instalador mais robusto e mais personalizado.

No final você poderá distribuir programas em python para desktops windows sem nenhum problema.

Muitas pessoas pensam que o Python serve só para fazer scripts e que não pode ser compilado e shipado. Mas não é bem assim, python também pode ser compilado e você pode distribuir software python sem o código-fonte.

Um grande exemplo disso é o Dropbox. O cliente do Dropbox foi escrito em Python para ser portável para Windows, Mac e Linux e a única diferença é que para Windows e Linux ele roda o wxPython no UI e no Mac ele usa Python-ObjC. As próprias palavras do Guido Van Rossum são muito legais falando sobre isso:

 

“Python plays an important role in Dropbox’s success: the Dropbox client, which runs on Windows, Mac and Linux (!), is written in Python. This is key to the portability: everything except the UI is cross-platform. (The UI uses a Python-ObjC bridge on Mac, and wxPython on the other platforms.) Performance has never been a problem — understanding that a small number of critical pieces were written in C, including a custom memory allocator used for a certain type of objects whose pattern of allocation involves allocating 100,000s of them and then releasing all but a few. Before you jump in to open up the Dropbox distro and learn all about how it works, beware that the source code is not included and the bytecode is obfuscated. Drew’s no fool. And he laughs at the poor competitors who are using Java.”

O texto original dele é esse aqui!

9 Dicas de Como Ganhar Hackathons

Como ganhar hackathons parece um título bastante pretensioso, mas minha intenção é compartilhar o que aprendi nos 8 hackathons que já participei.

A primeira vez que participei foi em 2013 no Google Developer Bus, de lá pra cá acabei gostando da ideia e só no ano passado participei de mais 7 hackathons, 3 deles no Vale do Silício.

Pra quem não sabe, hackathon é uma maratona hacker, maratona de programação ou simplesmente um motivo pra juntar um monte de programadores em um lugar e virar uma ou mais noites programando, comendo pizza e bebendo cerveja.

Desses hackathons que participei fui premiado 3 vezes e é muito legal ganhar, as vezes você ganha dinheiro, as vezes um gadget, mas se for pra participar só pelo prêmio esqueça… Na maioria das vezes o prêmio é menor do que o valor das suas horas trabalhadas. Então o objetivo é a diversão, o networking e o aprendizado.

 

1 – Estude o Hackathon Antes

Existem 2 tipos principais de hackathon: Os voltados para programação e os voltados para startups. Se você souber de antemão em qual tipo de hackathon você está se metendo já poderá poupar muito trabalho e/ou estresse. A maioria dos hackathons mostra quem serão os juízes e de olho neles você já consegue saber com o que eles estão envolvidos.

Hackathons voltados para programação vão exigir mais do aspecto técnico do seu Hack, o demo será muito importante e ele precisa estar funcionando.

Hackathons voltados para startups estão preocupados com o modelo de negócio do seu projeto. Nesse tipo de hackathon é comum apresentações com slides, sem demo, com produtos inacabados e é possível ganhar apenas com uma apresentação. Não adianta se espernear, vários juízes que não são técnicos não sabem avaliar se o que você mostrou está funcionando ou se é uma animação no power point.

Como o Gabriel Pugliese me lembrou, é bom também ficar de olho nas Regras do Hackathon, podem ter regras específicas quanto ao software que você pode utilizar, se você precisa ou não deixar o projeto aberto no Github, etc…

Outro ponto importante são os critérios de avaliação do hackathon. Os critérios podem ter pesos e se o seu objetivo é ganhar, então foque nos critérios.

classificacao

Nem sempre o grau de desenvolvimento é o critério com maior peso. Participei do Samsung Ocean Hackathon no ano passado e esse era um hackathon um pouco diferente, ele teria apenas 11 horas de duração incluindo a apresentação e o julgamento, no final das contas tinha umas 9 horas de duração. Os critérios para julgamento eram Inovação, UX e Desenvolvimento e a maior nota de Inovação chegava a 9320 pontos enquanto a de desenvolvimento chega apenas a 200. É claro que com um número baixo de horas para programar eles não priorizariam o desenvolvimento, porém eu e meu grupo não nos atentamos às notas dos critérios. Escolhemos uma ideia sem muita inovação para podermos desenvolver em um tempo curto e conseguimos a maior nota de desenvolvimento mas ficamos em sétimo lugar. Detalhe: A equipe vencedora ficou com a menor nota de desenvolvimento. Mas os critérios eram claros e estavam escritos, nós não estudamos o projeto antes =/

2 – Tenha um bom Time

Você pode ser um Solo Developer, pode ser o melhor Full-Stack dos sete Mares ou ainda ser o maior jogador de squash do mundo. Em um hackathon você vai precisar de um time.

Até porque na maioria dos hackathons é obrigatório ter um time e é uma experiência muito bacana, vocês se xingam, jogam a culpa um no outro, cantam musiquinhas irritantes, assistem um monte de youtube poops e ainda por cima programam.

Se você puder ir com um time formado, chame pessoas que já trabalham bem com você, que vão se comprometer, segurar a barra quando você não aguentar mais e que seja divertido passar mais de 24 horas acordado ao lado delas.

No primeiro hackathon que fui tivemos um problema com um cara do time. Os times eram escolhidos numa espécie de sorteio. Cada pessoa que era sorteada escolhia uma ideia na parede e quando se juntavam 4 pessoas de áreas diferentes o time estava formado. Eu entrei como back-end developer, tinhamos uma frontend, um gerente de projetos e um designer. O designer era um cara super difícil, não deixou a frontend trabalhar, quis fazer o frontend sozinho, não aceitava nenhuma ideia, criticava tudo e tornou a vida de todo mundo um saco durante quase 3 dias, mas mesmo assim a experiência foi super válida, dezenas de kit-kats, várias amizades e contatos importantes e de quebra eu aprendi a usar o Django non-rel com o AppEngine.

Em quase todas as vezes que o time podia ir montado eu fui com o Roberto Civille, o cara já ganhou tantos hackathons que o pessoal já está chamando de Serial Hackathon Winner.

3 – Know Your Shit

Você não pode chegar completamente despreparado para um hackathon. Há espaço para aprender muitas coisas, mas não chegue com um ambiente recém formatado sem sua IDE preferida, sem os programas que você vai usar e sem saber como instalar coisas novas. O tempo é seu inimigo durante o hackathon. Se você perder uma hora pra configurar alguma coisa ou instalar o Phonegap no windows pode acabar sendo prejudicado e vai acabar irritando o pessoal do seu grupo.

4 – Tenha uma boa Ideia

Fácil falar, difícil de colocar em prática. Depois que você começa a frequentar hackathons você percebe que algumas ideias SEMPRE se repetem, principalmente nos hackathons voltados para startups. Tem a WishList, tem o Guia de Baladas, Compartilhamento de Eventos entre amigos, etc… Depois de alguns hackathons você vai ver que as ideias se repetem e vai ver que você mesmo tem essas ideias, elas são simples, são as primeiras ideias que vem à cabeça. Pensar na ideia não é perder tempo. Gaste o tempo pensando e discutindo a ideia, estude as APIs dos patrocinadores, quais terão que ser utilizadas, veja qual tipo de integração seria legal que existisse entre elas. Se for uma coisa útil, ótimo. Se não for, que seja divertida!

No começo de setembro eu participei do Techcrunch Disrupt Hackathon e vencemos na categoria Melhor uso da API do Concur. A ideia partiu do Roberto, que queria ser lembrado de lugares que ele já tinha visitado em San Francisco. A partir dessa ideia, resolvemos desenvolver o mínimo que daria para provar o conceito em apenas 24 horas. Como eu tenho experiência com softwares e APIs de viagens como Sabre, Expedia e Regente eu acabei ficando com a API do Concur e o Roberto com a API do Evernote. Fizemos o BizMem um aplicativo que juntava todas as notas que foram criadas pelo usuário quando ele estava viajando e juntava com as informações de viagem fornecidas pela Concur, assim poderíamos melhorar a experiência de Viajantes à negócios. O pessoal do Evernote e do Concur gostou muito.

5 – Corte Requisitos

Não tente fazer tudo. Nos hackathons o legal é desenvolver coisas novas e não perder tempo com aquilo que todo mundo sabe. Se o login não for tão importante para o core do que você quer mostrar então corte o login. Se você não é viciado em testes, corte os testes. Corte o monte de ideias que vocês tiveram e deixe só o que dá pra fazer. Conforme o desenvolvimento for se desenrolando fique atento ao relógio, se estiver demorando demais em uma tarefa, veja se você não vai ter que compensar mais na frente ou se você terá que cortar aquela tarefa.

6 – Faça Perguntas

Como todo bom programador você deve estar acostumado a procurar pelas respostas sozinho. Ler documentações, perguntar no StackOverflow, abrir Códigos Fonte e etc. O problema é que as vezes a resposta para o que você busca não está tão fácil de achar e na maioria das vezes existe um developer advocate da API do patrocinador pronto para te ajudar durante o hackathon. Perguntar para esse cara é sempre uma boa ideia, primeiro porque ele tem mais experiência com aquela API do que você, segundo porque é uma forma de mostrar pra ele (que comumente é um Juiz) o que você está fazendo. Esses caras podem contribuir com dicas muito úteis sobre a sua ideia e sobre o desenvolvimento, não desperdice esta oportunidade!

Além disso, pergunte para outros participantes, converse com eles, vá tomar café, coma junto com eles, tente se entrosar, afinal todo mundo ali tem pelo menos alguma coisa em comum com você, assunto é o que não vai faltar

7 – Make it Work, Bitches!

Faça seu demo funcionar. Parece idiota, mas por incrível que pareça, em todos os hackathons que eu fui vi pessoas apresentando algo que não funcionava, ou porque viajaram demais na ideia, ou não sabiam usar a tecnologia que escolheram ou não souberam manejar o tempo cortando requisitos iniciais.

Só não vai queimar o fusível aí, o networking é muito importante. Trabalhe de forma inteligente pra fazer funcionar mas aproveite pra curtir a oportunidade de estar com outras pessoas.

8 – Spread the Word!

Teve a sua ideia e está conseguindo desenvolver? Comece a falar sobre ela! Mostre para os outros grupos, mostre para os patrocinadores, mostre para os juízes, o importante é você aproveitar a maior contribuição que eles podem te dar que é o Feedback. As apresentações geralmente são muito curtas e o seu produto pode não ser tão bem explicado naqueles poucos minutos que você vai falar, ou talvez você não apresente bem em público, então é melhor já mostrar seu produto pra todo mundo antes da apresentação. Se possível monte uma marca, faça as pessoas lembrarem do que você fez.

Em março de 2014 eu participei do API HackDay que era promovido pelo Twitter e pelo SendGrid. Nós inventamos um produto que chamamos de Vai Bilu, a ideia era poder fazer coisas pela internet usando apenas o email ou o twitter, porque alguns planos de celular dão acesso irrestrito ao Twitter ou ao seu E-mail. Fizemos em homenagem ao ET Bilu e ficamos o final de semana todo falando com a voz aguda do ET. No final das contas, ganhamos em primeiro lugar no Hackathon e todo mundo sabia o que era o Vai Bilu, estavam imitando o ET Bilu também e se divertindo com a gente. Virou uma marca! A fórmula deu tão certo que resolvemos homenagear o ET Bilu em mais duas ocasiões, no Angel Hack com o Toca Bilu (um brinquedo feito com Arduino) e no VemBilu uma espécie de Tinder para Estudar que ganhou em primeiro lugar na categoria Educação no Hackathon da CJE – FIESP

9 – Participe!

Quando o Andrés Sanches assumiu o Corinthians ele foi perguntado como ia fazer pra que o Corinthians ganhasse uma Libertadores e a resposta dele foi: Primeiro temos que participar mais! Depois disso o Corinthians se classificou várias vezes seguidas para a Libertadores e foi Campeão da Copa Libertadores da América de 2012.

Para ganhar hackathons você precisa fazer a mesma coisa: Participar! Óbvio que você não vai ganhar prêmio em todos, mas com certeza você vai ganhar outras coisas como conhecimento, networking, Freelas e fazer amigos.

Você pode ficar por dentro dos Hackathons nas comunidades do facebook como a Hackathons Brasil e dar uma olhada no Challenge Post

Bônus – Não se misture com a gentalha

Muitas pessoas querem só se aproveitar, principalmente dos mais inocentes. São pessoas que vão em um hackathon com uma Ideia já pronta, não sabem programar mas querem desenvolver um MVP de graça. Fique atento com essas pessoas, na maioria das vezes elas não querem que você contribua com ideias, querem só sua força de trabalho.

Já vi isso acontecer várias vezes e na maioria das vezes essas pessoas conseguem o que querem prometendo parcerias e etc. Tome cuidado! Vi isso até nos Estados Unidos no DataWeek + API World Hackathon. Nesse evento duas pessoas vieram com ideias e falando que não sabiam programar, como eu já tinha visto isso acontecer, disse que não tinha interesse e vi que essas pessoas passaram por todas as mesas antes de irem embora.

Bônus – A apresentação

Na hora de apresentar mostre o seu demo funcionando. Deixe que as pessoas o testem. Responda as perguntas que foram feitas antes, quando você recebeu o feedback dos outros participantes do hackathon. Fale das APIs que você usou, mostre o que aprendeu e faça a apresentação ser legal, afinal todo mundo está cansado de ficar ali.

O principal na hora da apresentação: Nunca confie na Internet. Pode ser que não tenha na hora da apresentação e dê tudo errado, tenha o que você precisar rodando localmente também, se der algum problema você mostra a versão local e sem crise.

Fizemos um hack muito legal, o NewsMood.me, que mostrava o humor das notícias relacionadas a um termo e na hora da apresentação a internet falhou, ou seja, não deu pra apresentar =(

Data Scraping das lojas do Buscapé com Python e Beautiful Soup

Nessa altura do campeonato todo mundo já sabe o que é Web Scraping, Scraping ou Data Scraping, mas vamos lá: É a varredura de um site ou de outro programa para extração de dados. Fiz isso a vida toda, aliás, meu primeiro estágio em 2002 envolvia muito disso, Eu pegava os dados de sites como Guia Mais, Listas OESP, etc, fazia o tratamento das informações e colocava em um mapa no qual os Gênios do Marketing utilizavam as informações pra fazer análises inteligentes de ações de marketing em áreas específicas. Eu achava o máximo!

Há a discussão se isso é legal ou não é legal, mas os dados estão abertos na internet e se não há nada especificado nos termos de uso do site então você pode sim fazer o data scraping. Inclusive o próprio Buscapé começou assim.

Um desses dias procurei na internet por alguma lista de e-commerces brasileiros e não achei nada, então pensei em ver se tinha alguma coisa no buscapé, já que ele agrega dezenas de e-commerces. Bom, achei essa página aqui que possui as informações das lojas cadastradas no buscapé: http://www.buscape.com.br/pesquise-uma-loja.html?pg=1.  Esse pg na query string é o número da página que estamos, obviamente.

Essa é a carinha da página:
buscape-pesquisa-uma-loja

 

Você pode ver que essa página é uma lista paginada das lojas cadastradas no buscapé. E isso se segue até a página 21270 mostrando 12 empresas por página.

buscape-rodape

E pra cada e-commerce que você clicar você vai ver várias informações sobre a empresa:

buscape-ricardo-eletro

 

Até aí, tudo fácil. Só achei a página com a lista de empresas, vi que ela tem uma paginação da página 1 até a página 21270, contém 12 lojas por página e que pra pegar as informações completas é necessário entrar no link de cada uma das lojas. Esse é o algoritmo, agora pra fazer isso acontecer tem que criar o script python.

Eu decidi criar 2 scripts, um para pegar o link de todas as lojas de cada uma das páginas da lista e o segundo para entrar em cada link de empresa e retirar essas informações colocando num Excel gigantesco.

Então, organizando, o primeiro script faz isso aqui:

  1. Encontrar qual elemento da página de listagem contém o link para as lojas
  2. Varrer todas as páginas de listagem para pegar os links individuais de cada página de loja
  3. Salvar esses links em um arquivo Excel (pode fazer de qquer outro jeito, eu quis assim)

Primeiro de tudo, você precisa encontrar na estrutura da página os elementos HTML e CSS que contêm os links que precismos retirar. Eu usei o Dev Tools do Chrome pra inspecionar o elemento e vi que todas as lojas estão em uma DIV que contém uma classe chamada size1of3 e é essa classe que vou utilizar para pegar todas as lojas. Dê uma olhada na figura:

buscape-div-loja

 

O trecho HTML das divs é normalmente assim:

<div class="unit size1of3">
 <div class="bp_shop_info line">
 <div class="shop_info_inner">
 <div class="main">
 <div class="leftCol name">
 <a data-preco="" title="Extra.com.br" href="http://www.buscape.com.br/empresa/avaliacao-sobre-extra-com-br--77.html">
 <img alt="Extra.com.br" src="http://imagem.buscape.com.br/vitrine/logo77.gif">
 </a>
 </div>
 <div class="features_wrapper main">
 <div class="line">
 <div class="speech_bubble_pointer">
 &nbsp;
 </div>
 <div class="inner">
 <div class="features_list main rounded_corner radius10">
 <ul class="features_inner">
 <li class="info_ebit_rating line">
 <a class="ico_ebit sprite_ico ebit_40 leftCol" title="Loja e-bit Excelente" target="_blank" href="http://www.ebit.com.br/lojas_virtuais/html/rateloja.asp?PnumNumEmpresa=2043">
 Loja E-bit e-bit Excelente
 </a>
 <div class="main">
 <a class="info_ebit ebit_ajuda" title="Loja e-bit Excelente" target="_blank" href="http://www.ebit.com.br/lojas_virtuais/html/rateloja.asp?PnumNumEmpresa=2043">
 e-bit Excelente
 </a>
 <span class="ratings">
 Avaliada por 
 <a href="http://www.buscape.com.br/empresa/avaliacao-sobre-extra-com-br--77.html">
 237.812 pessoas
 </a>
 </span>
 </div>
 </li>
 <li>
 <a title="Clique para ver mais informações" target="_blank" href="http://www.buscape.com.br/empresa/avaliacao-sobre-extra-com-br--77.html" class="sprite_ico info_shop">
 Mais detalhes da loja
 </a>
 </li>
 <li class="sprite_ico operation_area">
 Vende pela Internet
 </li>
 </ul>
 </div>
 </div>
 </div>
 </div>
 </div>
 </div>
 </div>
</div>

Dentro dessa div nós podemos pegar o primeiro link que aparece e extrair dele o title, que é o nome da loja e o href com o link para a página específica daquela loja. Eu escrevi isso em javascript mesmo, testei no Console e vi que funcionava


$('.size1of3').each(function() {var x =  $(this).find('a:first');console.log(x.attr('title') + ' ' + x.attr('href'))});

Agora vamos escrever o script em Python!


#URL http://www.buscape.com.br/pesquise-uma-loja.html?pg=1
#from 1 to 21265
# $('.size1of3').each(function() {var x = $(this).find('a:first');console.log(x.attr('title') + ' ' + x.attr('href'))});
import requests
import bs4
import openpyxl
import logging
from openpyxl import Workbook

#iniciar o arquivo de log
logging.basicConfig(filename='arq_links.log',level=logging.WARNING)

#iniciar a planilha do excel otimizada para escrita
wb = Workbook(write_only = True)
ws = wb.create_sheet()

for i in range(1,21266): 
    try:
       payload = {'pg':str(i)}
       response = requests.get('http://www.buscape.com.br/pesquise-uma-loja.html', params = payload)

       soup = bs4.BeautifulSoup(response.text)

       for div in soup.find_all(class_='size1of3'):
           ws.append([
           div.find('a')['title'], 
           div.find('a')['href'],
           'http://www.buscape.com.br/pesquise-uma-loja.html?pg=%s' % i,
           i,
       ])
 
       print "#%s" % i,

 except Exception as err:
     print "Erro na pagina %s" % i
     logging.exception(u"Erro na pagina %s" % i) 


wb.save('lojas.xlsx')

Estou usando o requests pra dar o GET na página e sempre passo como a query string (a variável payload) a página que quero dar GET.


payload = {'pg':str(i)}
response = requests.get('http://www.buscape.com.br/pesquise-uma-loja.html', params = payload)

Eu faço agora o parse desse resultado que vem no response.text usando o Beautiful Soup pra pegar apenas as informações que eu quero, no caso o nome da loja e o link para a página individual dela. Também resolvi salvar o link da página em que estou.

soup = bs4.BeautifulSoup(response.text)

for div in soup.find_all(class_='size1of3'):
    ws.append([
      div.find('a')['title'], 
      div.find('a')['href'],
      'http://www.buscape.com.br/pesquise-uma-loja.html?pg=%s' % i,
      i,
    ])

Estou usando o openpyxl que é excelente pra criar arquivos XLSX e também resolvi criar um log pra ver quais páginas podem ter dado errado por algum motivo. Assim é possível ver quais páginas ficaram de fora da sua lista e rodá-las novamente.

Enfim, rodando esse arquivo temos como saída um arquivo chamado lojas.xlsx com a lista de todas as lojas e com os links para a página individual delas. Então a parte um foi concluída, agora só falta entrar em cada uma dessas lojas e pegar os dados delas.

O segundo script deve fazer isso aqui:

  1. Vamos verificar como é o HTML + CSS de cada página de loja para saber como vamos fazer o scraping.
  2. Ler o arquivo excel gerado pelo primeiro script que contém o link de cada loja.
  3. Entrar em cada página e pegar os dados relevantes disponíveis
  4. Salvar tudo em um XLSX gigante

Pra verificar o formato HTML a gente pode inspecionar o elemento de novo dentro da página da loja. O que dá pra ver é que a div principal que contém os dados tem a classe company-header. Nessa div você pode pegar a classificação Ebit da loja, a descrição da loja e uma lista de informação de contatos que não é a mesma para todos os contatos, alguns tem informação como e-mail, telefone e outros não, então vamos ter que driblar (“Dibrar”) isso.

O bom é que todas essas informações de contato estão em uma lista e podemos pegar todos os elementos <li> desta lista e salvar em uma lista python. Depois podemos parsear essas informações e colocá-las em colunas certinhas num banco de dados, por enquanto só vou focar em pegar os dados.

O script fica assim:

import requests
import bs4
import openpyxl
import logging
from openpyxl import load_workbook
from openpyxl import Workbook

#iniciar o arquivo de log
logging.basicConfig(filename='arq_lojas.log',level=logging.WARNING)

#Abrindo o excel de leitura
wb = load_workbook(filename = 'lojas.xlsx', use_iterators = True)
ws = wb.get_sheet_by_name(name = 'Sheet1')

#iniciar a planilha do excel de excrita
wb_escrita = Workbook(write_only = True)
ws_escrita = wb_escrita.create_sheet()

for row in ws.iter_rows():
    try:
        nome = row[0].value
        url = row[1].value
        response = requests.get(url)
        soup = bs4.BeautifulSoup(response.text)

        div = soup.find(class_='company-header')
        ebit = ''
        if div.find('img'):
            if div.find('img').has_attr('title'):
                ebit = div.find('img')['title']

 
        desc = div.find(class_='about').string

        div = soup.find(class_='company-contacts')
        lista = []
        for li in div.find_all('li'):
            lista.append (li.text)

        ws_escrita.append(
            [nome,
            url,
            ebit,
            desc] + lista #Adicionando a lista de contatos daquela loja
        )
    except Exception as err:
        print "Erro na pagina %s" % url
        logging.exception(u"Erro na pagina %s" % url) 

wb_escrita.save('lojas_final.xlsx')

Ficou bem parecido com o primeiro arquivo. Agora é só executar os scripts. Execute o primeiro, ele vai demorar algumas horas até terminar, depois execute o segundo script. Aqui demorou bastante, quase 20 horas pra executar tudo.

O resultado final com os arquivos de excel e o código fonte você pode ver aqui no meu github: https://github.com/ffreitasalves/buscape-scraper

Projeto Django privado para código aberto sem comprometer a segurança

Uma vez resolvi passar um projeto django que fiz de fechado para aberto e acabei colocando as senhas que usava no servidor de emails no GitHub. É mole?

Bom, se o projeto é novo recomendo o seguinte, nunca coloque dados secretos no seu settings.py e dentro do git, inclusive o SECRET_KEY gerado.faça o seguinte, crie um arquivo settings_local.py na mesma pasta que o seu settings.py

Neste arquivo coloque toda a informação que você não quer que seja compartilhada, como por exemplo:

  • SECRET_KEY
  • EMAIL_HOST_PASSWORD (E outras configurações de Email)
  • SOCIAL TOKENS (como para Facebook e Twitter)
  • etc…

No final do seu arquivo settings.py importe tudo que estiver no settings_local.py:

 try:
     from settings_local import *
 except ImportError:
     pass

Agora você precisa adicionar o settings_local no .gitignore para que ele não seja enviado durante seus commits. Se você ainda não criou o arquivo faça o seguinte:

touch .gitignore
vim .gitignore

Dentro desse arquivo coloque o caminho relativo do seu settings.py, no caso <nome_do_app>/settings_local.py e depois adicione seu gitignore no git.

git add .gitignore
git commit -m "Ignorando o settings local"

Pronto, agora você consegue continuar programando sem se preocupar em colocar dados que não deveria em um projeto OpenSource.

Mas e se você já estava fazendo tudo sem isso e o resto dos dados estão todos no histórico do GIT? Você pode usar o BFG Repo-Cleaner ou o git-filter-branch.