Cris Motinha
3 min readApr 19, 2017

Não tem jeito melhor de aprender alguma teoria se não utilizando-a no mundo real. E como a necessidade faz o homem, e o homem as oportunidades*, precisei de um webcrawler e resolvi aprender a fazer.

O contexto é: estou participando de um concurso onde a foto mais votada vai ganhar hotel e passagem pro MongoDB World 17 (#MDBW17), e como eu estou doida pra ir (porém não tenho $patrocinadore$), resolvi investir pesado em campanha pedindo pra todos os amigos, avós, cachorros e gatinhos votarem em mim. Só que o site não fornece algo muito útil para quem quer ver quem está ganhando: um raking (ou um pódium).

Então resolvi colocar a mão na massa, e listo abaixo os meus avanços, de forma bem breve. Todo o meu código está nesse repositório, e eu super aceito comentários e pull requests :)

  1. Posso fazer um web crawler?
    A primeira coisa que me preocupou foi exatamente isso: posso fazer um webcrawler e buscar informações e coletar e tudo mais? Pesquisando no Lord Google, descobri que esse tipo de restrição é feita em um arquivo robots.txt, e que para acessá-lo, era só colocar depois da url. Tentei todas as combinações possíveis na url do concurso, e não encontrei nada. Sinal verde então :)
  2. Qual linguagem?
    Como eu não teria muito tempo para fazer (umas 4h no domingo e mais umas 3h de hotfix hoje), resolvi fazer em Python3, que é a linguagem de backend que mexo com mais facilidade, e usar o Flask para fazer os requests (por ele ser bem simples).
  3. E agora, por onde começo?
    Comecei seguindo esse material, que logo de cara me mostrou tudo que eu ia precisar usar nesse projeto: as libs urllib e BeautifulSoup (BS4).

Minha primeira abordagem foi inspecionar o máximo que eu podia da página da galeria. Olhei o html, importei as bibliotecas e dei print no que o BS4 baixava, e com isso descobri que eles guardavam as informações dos participantes num script, numa variável chamada “var context”.

Dela, puxei as informações que eu precisava (nome e número de votos), botei num array, ordenei e pluft! Estava pronto o ranking.

Arrumei um template (aqui), e usei o jinja (que já vem no flask) para renderizar as informações na página. Depois juntei todo o código de crawl, joguei numa grande função (na verdade duas, dá pra ver nesse commit) e chamei ela no app.py.

Fiz o primeiro deploy hoje de manhã cedo, e tudo parecia ir bem. Até que umas 15h30 recebo uma mensagem de uma amiga me dizendo que achou um bug :( Eis que aquela var context só pegava as pessoas da pagina atual, e ignorava as outras páginas. Eu estava em primeiro lugar, só que primeiro lugar da primeira página somente…

E foi daí que surgiu o hotfix: fazer esse crawler pegar todas as páginas. Mas como que é a url para as outras páginas, se no navegador ao passar de página nada muda? Inspecionando os requests enquanto clicava para a próxima página, achei o pote de ouro: a url que retornava o json purinho lindo e maravilhoso com todas as informações que iam parar naquela variável. Agora era só pegar esse json em todas as páginas e PRONTO!

E foi aí que tive diversos problemas, que resolvi da forma mais boba possível: retirando o BS4 da função que pegava o JSON. Ele junto como json.loads fazia uma confusão de encoding que escapava e não escapava novas linhas e outros caracteres. Daí passei o parse direto no page.read() (page é a página lida pelo urllib) e funcionou!

Último passo foi descobrir afinal quantas vezes teria que iterar para montar a lista com todos os participantes (ou seja, visitando todas as urls). Copiei todo o javascript que o Inspect do Firefox pode me dar do site, e joguei no Sublime para inspecionar. Achei uma variável muito conveniente chamada totalPages, que vinha num JSON como total_pages. Só que esse JSON eu não achei. Peguei o código antigo (o que realmente lia a tag script) e usei ele para achar essa variável, até porque esse número é fixo para todas as páginas.

E foi assim que consegui fazer um web crawler, em pouquíssimo tempo, muitos erros e um código um tanto vergonhoso, mas que funciona!

Ele está deployado no Heroku, nesse link: http://contest-crawler.herokuapp.com/ e novamente, é esse o repositório: https://github.com/crismotinha/mongo_crawler

E se você leu até aqui, muito obrigada pela paciência e me dá uma forcinha votando em mim! (aqui ou pelo botão na página do crawler :) )

*Não sei de quem é a citação, vou chutar Clarisse Lispector