Quantcast
Channel: Planet Python
Viewing all articles
Browse latest Browse all 22462

PythonClub - A Brazilian collaborative blog about Python: Raspando a Web com Python: Introdução

$
0
0

Todo projeto que deseja raspar dados da web se resume ao seguinte loop:

  1. Fazer uma requisição para uma URL;
  2. Processar a resposta (HTML, XML ou JSON);
  3. Extrair os dados;
  4. Deduzir as próximas URLs a visitar;
  5. Repetir o loop.

A parte mais difícil aqui é processar o HTML. É um processo todo delicado, o HTML é cheio de detalhes para tolerar tags que não fecham, símbolos largados nos lugares errados e por aí vai. Por isso é difícil ter um parser (processador) de HTML nas bibliotecas-padrão de qualquer linguagem, seja Python, Ruby, Javascript ou PHP. Já XML e JSON são formatos muito mais estritos e tem parsers nativos em qualquer linguagem.

Vamos ver como pegar os gastos da Copa do Mundo 2014, expostos em XML. Alguns browsers vão exibir o XML como uma árvore, facilitando a visualização da estrutura -- meu browser favorito, o Firefox, faz isso.

Nesse XML você pode ver um elemento maior, o collection, com muitos elementos copa:empreendimento dentro. Esse prefixo copa: corresponde a um namespace, um recurso do XML para poder misturar elementos de vocabulários distintos. É importante prestar atenção nisso para podermos informar o nosso parser de XML.

Para começar o loop, vamos carregar a URL e popular uma árvore de elementos -- uma abstração do Python para podermos manipular mais facilmente esses dados:

fromxml.etreeimportElementTreefromurllib.requestimporturlopendata_url="http://www.portaltransparencia.gov.br/copa2014/api/rest/empreendimento"withurlopen(data_url)asdatafile:data=ElementTree.parse(datafile)

Repare como carregar uma URL no Python 3 tem uma sintaxe confortável, idêntica à sintaxe de abrir arquivos. Agora pra seguir o loop, vamos extrair o que nos interessa: o gasto (valorTotalPrevisto) de cada empreendimento iniciado ou concluído (cujo andamento não esteja no estado 1, Não iniciado).

spending=[float(element.find('./valorTotalPrevisto').text)forelementindata.iterfind('.//copa:empreendimento',namespaces={'copa':data_url[:46]})ifelement.find('./andamento/id').text!='1']

Pegar elementos de um ElementTreeé fácil usando o método iterfind (retorna um iterável, pra usar com for) ou findall (retorna uma lista propriamente dita). Já pegar o conteúdo de um elemento exige apenas chamar o atributo .text. Fácil, não?

Isso daria certo se os dados fossem consistentes, mas... outro porém! O XML é estrito -- as tags fecham, os símbolos estão no lugar certo, está tudo certo, mas os dados em si não são consistentes. Nem todo elemento copa:empreendimento tem um elemento valorTotalPrevisto dentro. E agora?

É simples: vamos encapsular o processamento desse valor em um método simples, que retorna zero quando não existe valor total previsto (pra facilitar a soma, depois).

defget_cost(element):cost=element.find('./valorTotalPrevisto')return0if(costisNone)elsefloat(cost.text)

Agora basta chamar o get_cost na nossa compreensão de lista:

spending=[get_cost(element)forelementindata.iterfind('.//copa:empreendimento',namespaces={'copa':data_url[:46]})ifelement.find('./andamento/id').text!='1']

E aí podemos finalmente somar todos os valores encontrados e imprimir usando o poderoso método format do Python (estude!).

print('Foram gastos {total:.2f} dinheiros do governo brasileiro'.format(total=sum(spending)))

Bônus: Uma versão mais idiomática (PYTHONICA) do código está disponível no meu Gist. Fique à vontade para contribuir, comentar, melhorar, etc :)

Agradecimentos ao Fernando Masanori que começou a brincadeira com esses dados!


Viewing all articles
Browse latest Browse all 22462

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>