Usando dicts para organizar listas de deputados e seus partidos
Para este laboratório vamos precisar alguns conceitos novos:
Como sempre procure a documentação detalhada dos módulos usados na internet (Google, etc)
- Download de arquivos da internet
- Ler arquivos xlsx (Excel)
Como sempre procure a documentação detalhada dos módulos usados na internet (Google, etc)
Download de arquivos
Páginas de sites na web são transferidas e salvas em arquivos texto, mas num formato conhecido como HTML. Ao abrir uma página no browser este envia ao site um pedido de transferência de um arquivo html correspondente. Este arquivo contém toda informação necessária para o browser exibir a imagem da página na forma desejada.Em nosso caso vamos usar um script em Python para efetuar o download de arquivos em vez de usar um browser. O download de arquivos html é semelhante à leitura de arquivos texto que já vimos. A complexidade da interação com a rêde e sites remotos fica escondida num módulo chamado requests.
Para baixar um dado arquivo html vamos precisamos de seu "caminho", como no caso de arquivos texto. Aqui o caminho é uma url, um mapa único de como navegar a rêde para chegar ao arquivo desejado.
Vamos exemplificar baixando um arquivo do site da Câmara de Deputados do Brasil. A url deste site é http://www2.camara.leg.br/ e quando digitamos esta url no Firefox ou Chrome aparece uma página de boas vindas da CD.
Para nós nada vai aparecer, pois vamos somente baixar o arquivo html e depois salvá-lo no computador. Note que os caminhos de arquivos aqui mostrados são especificos para o meu computador. No seu os caminhos serão diferentes.
Primeiro vamos importar o módulo requests e alguns módulos úteis adicionais.
In [1]:
import os, requests
os.chdir(r'C:\Users\ps\Desktop\Blog')
# define a url da CD
url = 'http://www2.camara.leg.br/'
Baixar o arquivo fica "trivial" porque o módulo requests
faz todo o trabalho para nós. Entretanto os mais diversos problemas
podem ocorrer (site fora do ar, arquivo foi movido dentro do site, não
temos permissão de acesso, acesso à internet caiu, etc) e o download
pode falhar. O módulo requests joga uma Exception (exceção) para avisar o usuário que tipo de problema houve. Cabe a nós capturarmos alguma Exception eventual e fazer algo a respeito. Fazemos isto do modo já visto, usando os comandos try e except.
Vamos lá.
O comando get(uma_url) do módulo request é quem faz quase todo trabalho de download. Uma vez executado é necessário testar o status do objeto criado por request.get(uma_url) para verificar se ocorreram problemas durante a conexão com o site remoto. Tipicamente se usa o comando raise_for_status() do objeto criado, o qual joga qualquer exceção associada ao objeto.
In [2]:
res = requests.get(url)
try:
res.raise_for_status()
except Exception as ex:
msg = 'There was a web problem: %s' % (ex)
print(msg)
type(res) # verifica o tipo de objeto criado pelo get()
Out[2]:
O objeto res que obtivemos ainda não é o arquivo
desejado mas somente uma espécie de acesso ao arquivo. Para obter o
corpo do arquivo precisamos usar res transferindo os
dados que ele disponibiliza. Estes dados vem em blocos, em formato
binário. Salvamos os blocos escrevendo-os num arquivo binário.
In [3]:
src = os.getcwd()
path = os.path.join(src,'camara.htm')
htm = open(path, 'wb')
for chunk in res.iter_content(100000):
htm.write(chunk)
htm.close()
print(path)
Verifique que um arquivo "camara.htm" aparece no caminho path
em seu computador. Depois clique no arquivo, o que deve abrir seu
browser mostrando o conteúdo do arquivo (a primeira página do site da
Câmara dos Deputados). Para verificar que o arquivo aberto realmente é
local no seu computador, observe que o caminho mostrado no browser deve
ser algo como file:///C:/Users/ps/Desktop/Blog/camara.htm Note que começa com file://... em vez de http://...
Lendo arquivos xlsx do Excel
O módulo que permite ler planilhas Excel chama-se xlrd. Vamos importá-lo.
In [4]:
import xlrd
Neste módulo o comando xlrd.open_workbook(uma_path) devolve um objeto que representa o workbook que está no caminho uma_path. Ou seja, a planilha.
In [5]:
path = r'C:\Users\ps\Desktop\Blog\aula6\Book1.xlsx'
wb = xlrd.open_workbook(path)
O objeto wb recem criado representa a planilha book1.xlsx que usaremos como exemplo neste exercicio.
O objeto wb (workbook) por sua vez oferece uma série de comandos. Em particular podemos obter os nomes de sheets (folhas) da planilha e com estes nomes podemos criar objetos que representem sheets especificos.
In [6]:
sheets = wb.sheet_names()
sname = sheets[0]
sname
Out[6]:
In [7]:
sheet = wb.sheet_by_name(sheets[0])
type(sheet)
Out[7]:
Com o objeto sheet podemos invocar um monte de comandos que permitem ler o conteudo de celulas e outras coisas uteis.
In [8]:
sheet.nrows # o numero de linhas desta planilha
Out[8]:
In [9]:
sheet.ncols # e o numero de colunas
Out[9]:
Células da planilha podem ser acessadas com o comando sheet.cell(rw,cl) onde rw e cl
são o número (começando de 0) de uma linha e de uma coluna
respectivamente. Já o valor contido numa célula é lido com o comando sheet.cell(rw,cl).value
In [10]:
titulo = sheet.cell(0,0).value
titulo
Out[10]:
In [11]:
nome = sheet.cell(1,0).value
nome
Out[11]:
In [12]:
partido = sheet.cell(1,1).value
partido
Out[12]:
Vejamos como iterar sobre todas as linhas desta planilha, imprimindo o que encontramos.
In [13]:
for rw in range(sheet.nrows):
# pega o nome politico
cl = 0
nome = sheet.cell(rw,cl).value
if nome == None:
break
# pega o partido
cl = 1
partido = sheet.cell(rw,cl).value
# pega o status
cl = 3
status = sheet.cell(rw,cl).value
#imprime a linha
print(nome, partido,status)
Bem com isto vimos os pre-requisitos para nosso laboratório de hoje.
Aula 6 - laboratório
Nosso objetivo neste exercício será baixar duas planilhas de um site da internet, comparar seus conteúdos e imprimir as diferenças. Este exercício ilustra os conceitos usados no script dep.py que usamos no NECI para monitorar continuamente (quase) as mudanças de partidos e de status dos deputados da CD.
As urls das planilhas são respectivamente:
Você já sabe como baixar os respectivos arquivos e como abrir depois os workbooks Excel para ler os seus conteúdos. O que falta agora é bolar o algoritmo para comparar estes conteúdos, identificar o que for diferente e imprimir o resultado.
- https://dl.dropboxusercontent.com/u/50004393/Book1.xlsx
- https://dl.dropboxusercontent.com/u/50004393/Book2.xlsx
Você já sabe como baixar os respectivos arquivos e como abrir depois os workbooks Excel para ler os seus conteúdos. O que falta agora é bolar o algoritmo para comparar estes conteúdos, identificar o que for diferente e imprimir o resultado.
Primeiro vamos baixar os dois books em nosso diretório de
trabalho. Para baixar tudo vamos ter que escrever duas vezes trechos de
códigos quase identicos. Além de ser uma tarefa entediante existe a
chance de cometer erros.
Por esta razão vamos colocar numa função o código de download e salvamento em arquivo. Depois é só chamar duas vezes.
Por esta razão vamos colocar numa função o código de download e salvamento em arquivo. Depois é só chamar duas vezes.
A função baixa(url, nomearq) recebe a url completa donde baixar o arquivo e um nome desejado para o arquivo salvo no diretório corrente.
In [14]:
'''url é a url do arquivo remoto a ser baixado, arq é o nome desejado
para o arquivo local'''
def baixa(url, arq):
# cria conexão com o arquivo remoro
res = requests.get(url)
try:
res.raise_for_status()
except Exception as ex:
msg = 'There was a web problem: %s' % (ex)
print(msg)
return
# agora copia o conteudo do arquivo remoto
src = os.getcwd()
path = os.path.join(src, arq)
xl = open(path, 'wb')
for chunk in res.iter_content(100000):
xl.write(chunk)
xl.close()
print('Baixou ' + arq)
Agora é só definir as urls, os nomes dos arquivos locais e chamar nossa função baixa()
In [15]:
url1 = r'https://dl.dropboxusercontent.com/u/50004393/Book1.xlsx'
url2 = r'https://dl.dropboxusercontent.com/u/50004393/Book2.xlsx'
arq1 = 'dep1.xlsx'
arq2 = 'dep2.xlsx'
# baixa a primeira planilha
baixa(url1, arq1)
# baixa a segunda planilha
baixa(url2,arq2)
Se tudo foi bem e os arquivos Excel estão salvos no diretório
(observe que em seu computador os caminhos podem ser diferentes!), então
agora falta fazer a comparação dos conteúdos.
Isto pode ser feito de diversas formas e vamos ilustrar aqui a maneira que usamos no script do NECI.
A idéia é usar dicionários dict para armazenar o conteúdo de uma planilha destas. A chave de cada item do dicionário é o nome do deputado, que supomos ser imutável. O valor de cada item é uma tupla contendo seu partido e seu status naquela planilha.
Vejamos como fica a primeira planilha.
Isto pode ser feito de diversas formas e vamos ilustrar aqui a maneira que usamos no script do NECI.
A idéia é usar dicionários dict para armazenar o conteúdo de uma planilha destas. A chave de cada item do dicionário é o nome do deputado, que supomos ser imutável. O valor de cada item é uma tupla contendo seu partido e seu status naquela planilha.
Vejamos como fica a primeira planilha.
In [18]:
src = os.getcwd()
path1 = os.path.join(src, arq1)
wb = xlrd.open_workbook(path1)
sheets = wb.sheet_names()
sheet = wb.sheet_by_name(sheets[0])
sheet.nrows # se tudo foi bem deve imprimir o numero de linhas
Out[18]:
Agora implementamos nossa ideia. Primeiro criamos um dicionario vazio, depois percorremos as linhas da planilha sheet criando cada item do dicionário e inserindo-o.
In [19]:
# cria dicionario com colunas nome, partido e status
dic1 = {}
for rw in range(1, sheet.nrows):
# pega o nome politico
cl = 0
nome = sheet.cell(rw,cl).value
if nome == None:
break
# pega o partido
cl = 1
partido = sheet.cell(rw,cl).value
# pega o status
cl = 3
status = sheet.cell(rw,cl).value
item = [partido, status]
dic1[nome] = item
In [20]:
import pprint
pprint.pprint(dic1)
Muito bem até aqui. Agora vamos repetir tudo isto para a segunda planilha, obtendo outro dicionário dic2
In [22]:
path2 = os.path.join(src, arq2)
wb = xlrd.open_workbook(path2)
sheets = wb.sheet_names()
sheet = wb.sheet_by_name(sheets[0])
# cria dicionario com colunas nome, partido e status
dic2 = {}
for rw in range(1, sheet.nrows):
# pega o nome politico
cl = 0
nome = sheet.cell(rw,cl).value
if nome == None:
break
# pega o partido
cl = 1
partido = sheet.cell(rw,cl).value
# pega o status
cl = 3
status = sheet.cell(rw,cl).value
item = [partido, status]
dic2[nome] = item
pprint.pprint(dic2)
É evidente que existem diferenças. Por exemplo, apareceu um tal Adail
Carneiro, que não aparecia na planilha anterior. Alem disto houve
diversas trocas de partidos, por exemplo os primeiros dois eram de PMB e
foram para o DEM e para o PP respectivamente.
Vejamos como detetar as diferenças usando estes dicionários.
Vamos detetar dois tipos de diferenças.
Vejamos como detetar as diferenças usando estes dicionários.
Vamos detetar dois tipos de diferenças.
- nomes que aparecem num dicionário e não aparecem no outro
- partidos diferentes nos dicionários para o mesmo nome
A primeira função compara(a,b) compara dois dicionários de nosso tipo e devolve duas listas (que podem estar vazias). A primeira lista são nomes que estão em a mas não estão em b, e a segunda lista é o reverso.
In [23]:
def compara(a, b):
'''a and b are dictionaries. Returns lists with keys in a that
are not in b and keys in b that are not in a'''
dif1 = []
for n in a.keys():
if n not in b.keys():
dif1.append(n)
dif2 = []
for n in b.keys():
if n not in a.keys():
dif2.append(n)
return (dif1, dif2)
A segunda função difpartidos(a,b) returna um dicionário onde a chave é o nome de um deputado e o valor é uma lista com o partido dele em a seguido do partido dele em b.
In [24]:
def difpartidos(a,b):
'''a and b are dictionaries. Returns dictionary where keys are
names that are in both a and b and value is a list with their
partido in a and in b'''
dif = {}
for n in a.keys():
if n in b.keys():
t1 = a[n]
t2 = b[n]
if t1[0] != t2[0]:
t = [t1[0], t2[0]]
dif[n] = t
return dif
Tendo estas funções fica fácil armar o corpo do algoritmo. Primeiro
testamos logo se os dicionários tem qualquer diferença, o que pode ser
feito com um mero teste de igualdade de objetos dic1 == dic2?
Caso os dicionários estejam diferentes usamos a função compara() para ver se apareceram ou sumiram nomes nas planilhas.
Continuando usamos a função difpartidos() para verificar eventuais mudanças de partidos.
Caso os dicionários estejam diferentes usamos a função compara() para ver se apareceram ou sumiram nomes nas planilhas.
Continuando usamos a função difpartidos() para verificar eventuais mudanças de partidos.
In [25]:
# compara os dois dicionários diretamente
if dic1 == dic2:
print('Nenhuma mudança detetada')
else:
# deteta nomes novos e faltantes
dif1, dif2 = compara(dic1, dic2)
if dif1:
print('Nomes que faltam em dic2')
pprint.pprint(dif1)
print()
if dif2:
print('Nomes que faltam em dic1')
pprint.pprint(dif2)
print()
# deteta mudanças de partidos
difp = difpartidos(dic1, dic2)
if difp:
print('Mudanças de partidos')
pprint.pprint(difp)
E isto encerra nosso laboratório de hoje, que visou ilustrar um dos inúmeros usos de dicionários num exemplo (proximo a) real.
No comments:
Post a Comment