Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Exemplo de código para acessar dados do Brasil.IO
import csv
import gzip
import io
import json
from urllib.parse import urlencode, urljoin
from urllib.request import Request, urlopen
class BrasilIO:
base_url = "https://api.brasil.io/v1/"
def __init__(self, auth_token):
self.__auth_token = auth_token
@property
def headers(self):
return {
"User-Agent": "python-urllib/brasilio-client-0.1.0",
}
@property
def api_headers(self):
data = self.headers
data.update({"Authorization": f"Token {self.__auth_token}"})
return data
def api_request(self, path, query_string=None):
url = urljoin(self.base_url, path)
if query_string:
url += "?" + urlencode(query_string)
request = Request(url, headers=self.api_headers)
response = urlopen(request)
return json.load(response)
def data(self, dataset_slug, table_name, filters=None):
url = f"dataset/{dataset_slug}/{table_name}/data/"
filters = filters or {}
filters["page"] = 1
finished = False
while not finished:
response = self.request(url, filters)
next_page = response.get("next", None)
for row in response["results"]:
yield row
filters = {}
url = next_page
finished = next_page is None
def download(self, dataset, table_name):
url = f"https://data.brasil.io/dataset/{dataset}/{table_name}.csv.gz"
request = Request(url, headers=self.headers)
response = urlopen(request)
return response
if __name__ == "__main__":
api = BrasilIO("meu-api-token")
dataset_slug = "covid19"
table_name = "caso_full"
# Para baixar o arquivo completo:
# Após fazer o download, você salvá-lo no disco ou percorrer o arquivo em
# memória. Para salvá-lo no disco:
response = api.download(dataset_slug, table_name)
with open(f"{dataset_slug}_{table_name}.csv.gz", mode="wb") as fobj:
fobj.write(response.read())
# TODO: o código acima pode ser melhorado de forma a não utilizar
# `response.read()` para não colocar todo oarquivo em memória e sim fazer
# streaming da resposta HTTP e salvar cada chunk diretamente no `fobj`.
# Caso queira percorrer o CSV em memória:
response = api.download(dataset_slug, table_name)
fobj = io.TextIOWrapper(gzip.GzipFile(fileobj=response), encoding="utf-8")
reader = csv.DictReader(fobj)
for row in reader:
pass # faça algo com `row`
# Para navegar pela API:
filters = {"state": "PR", "is_last": True}
data = api.data(dataset_slug, table_name, filters)
for row in data:
pass # faça algo com `row`
@ramongss

This comment has been minimized.

Copy link

@ramongss ramongss commented Jul 6, 2020

Tentando ajudar e fazendo minha contribuição para esse projeto 📊.

Traduzi o código para R:

download_brasilio_table <- function(dataset, table_name){
  url <- sprintf("https://data.brasil.io/dataset/%s/%s.csv.gz", dataset, table_name)
  tmp <- tempfile()
  download.file(url, tmp)
  response <- read.csv(gzfile(tmp), encoding = "UTF-8")
  unlink(tmp)
  return(response)
}

# Passe o nome da tabela para a funcao, como "caso", "caso_full", "obito_cartorio":
data <- download_brasilio_table("covid19", "caso_full")

Quem quiser propor melhorias, esse código em R também está aqui.

Parabéns para Álvaro e todos os colabores 👏👏👏.

@fccoelho

This comment has been minimized.

Copy link

@fccoelho fccoelho commented Jul 9, 2020

estou pegando um erro forbidden ao tentar baixar o https://data.brasil.io/dataset/covid19/caso_full.csv.gz direto do Pandas, mas via wget funciona normalmente

@giuliano-oliveira

This comment has been minimized.

Copy link

@giuliano-oliveira giuliano-oliveira commented Nov 11, 2020

Faltou um :

from tqdm import tqdm
@turicas

This comment has been minimized.

Copy link
Owner Author

@turicas turicas commented Nov 11, 2020

Faltou um :

from tqdm import tqdm

@giuliano-oliveira Opa, obrigado. Tirei ele do código de exemplo, pra ficar sem dependências. :)

@brunoorosco

This comment has been minimized.

Copy link

@brunoorosco brunoorosco commented Nov 12, 2020

é possível buscar os dados já filtrados, conforme formulário web? Estou fazendo uma aplicação mobile para trabalha da faculdade, eu gostaria de usar os dados para demonstração do app. Fiz o cadastro e criei o token, mas ainda sim não estou conseguindo acesso. Obrigado desde já.

@giuliano-oliveira

This comment has been minimized.

Copy link

@giuliano-oliveira giuliano-oliveira commented Nov 12, 2020

@brunoorosco mesma coisa comigo, tentei usar o cabeçalho WWW-Authentication, tbm não funcionou.

@turicas

This comment has been minimized.

Copy link
Owner Author

@turicas turicas commented Nov 12, 2020

@brunoorosco e @giuliano-oliveira Por favor, leiam os dois artigos que publiquei no blog sobre:

Nota: o nome do cabeçalho HTTP é Authorization e não WWW-Authentication.

@giuliano-oliveira

This comment has been minimized.

Copy link

@giuliano-oliveira giuliano-oliveira commented Nov 12, 2020

@turicas, eu li sobre, ajustei meu código e até tentei o script desse gist com meu token, mas sempre tá dando 401....

Traceback (most recent call last):
  File "test.py", line 79, in <module>
    for row in data:
  File "test.py", line 38, in data
    response = self.request(url, filters)
  File "test.py", line 28, in request
    response = urlopen(request)
  File "/usr/lib/python3.7/urllib/request.py", line 222, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/lib/python3.7/urllib/request.py", line 531, in open
    response = meth(req, response)
  File "/usr/lib/python3.7/urllib/request.py", line 641, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib/python3.7/urllib/request.py", line 569, in error
    return self._call_chain(*args)
  File "/usr/lib/python3.7/urllib/request.py", line 503, in _call_chain
    result = func(*args)
  File "/usr/lib/python3.7/urllib/request.py", line 649, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 401: Unauthorized
@brunoorosco

This comment has been minimized.

Copy link

@brunoorosco brunoorosco commented Nov 12, 2020

@turicas, já tentei o uso de Authorization e Authentication mas dois me retornaram 401, não autorizado

@giuliano-oliveira

This comment has been minimized.

Copy link

@giuliano-oliveira giuliano-oliveira commented Nov 12, 2020

Consegui, tem que mudar a linha 20 para:

            "Authorization": f"Token {self.__auth_token}",

porém agora tá dando 400 no método BrasilIO.download ....

@giuliano-oliveira

This comment has been minimized.

Copy link

@giuliano-oliveira giuliano-oliveira commented Nov 12, 2020

Para obter os dados completos em com as URLs começando com https://data.brasil.io/dataset/ Não coloque o cabeçalho Authorization somente o User-Agent

Para obter dados com filtros através da API com URLs começando com https://api.brasil.io/v1/ coloque o cabeçalho Authorization e User-Agent

@turicas

This comment has been minimized.

Copy link
Owner Author

@turicas turicas commented Nov 12, 2020

@giuliano-oliveira opa, você está certo. Fiz uma alteração no código, mudando a forma como self.headers é usado nas diferentes requisições (API vs download). @brunoorosco o novo código deve funcionar pra ti.

@brunoorosco

This comment has been minimized.

Copy link

@brunoorosco brunoorosco commented Nov 13, 2020

@turicas, obrigado, vou verificar!!

@elsonss1988

This comment has been minimized.

Copy link

@elsonss1988 elsonss1988 commented Nov 13, 2020

Para usar com JS poderia acessar usando https://api.brasil.io/v1/authorization/, está correto?

@turicas

This comment has been minimized.

Copy link
Owner Author

@turicas turicas commented Nov 13, 2020

@elsonss1988 não, essa URL não existe na API. Veja os 2 posts no blog que linkei em um comentário acima para fazer sua implementação.

@elsonss1988

This comment has been minimized.

Copy link

@elsonss1988 elsonss1988 commented Nov 16, 2020

Opa @turicas então poderia com algo similar

fetch('https://api.brasil.io/v1/', {
method: 'get',
mode:'basic'
headers: new Headers({
'Authorization': 'Basic '+btoa('elsonstz:2222222'),
}).then(console.log('sucess'))

@brunoorosco

This comment has been minimized.

Copy link

@brunoorosco brunoorosco commented Nov 17, 2020

@elsonss1988 - conseguiu utilizar com este cabeçalho em js?

@giuliano-oliveira

This comment has been minimized.

Copy link

@giuliano-oliveira giuliano-oliveira commented Nov 17, 2020

@elsonss1988 quase, vc precisa passar sua chave de api nos headers, após criar sua conta lá no site do brasil.io, assim como explica aqui.

Exemplo para NodeJS, (substitua o "meu-api-token" com sua chave de API):

const fetch = require('node-fetch');

const token="meu-api-token";

const datasetSlug="covid19";
const tableName="caso_full";

const filters = {state: "PR", is_last: "True"};

const url=`https://api.brasil.io/v1/dataset/${datasetSlug}/${tableName}/data?state=${filters.state}&is_last=${filters.is_last}`

fetch(
  url,
  {
    method: 'get',
    headers: {
      Authorization: `Token ${token}`,
    },
  }
).then(res => res.json())
.then(json => console.log(json));
@elsonss1988

This comment has been minimized.

Copy link

@elsonss1988 elsonss1988 commented Nov 19, 2020

@giuliano e @brunoorosco, muito obirgado pelo feedback, vou nesse fds testar a implementação e informo se consegui com sucesso ou se precisou de alguma implemetação.

@nativow

This comment has been minimized.

Copy link

@nativow nativow commented Nov 20, 2020

Uma dica para testar rapidamente a API é utilizar o site: https://reqbin.com/
URL de exemplo: https://api.brasil.io/v1/dataset/covid19/caso/data?state=AL&is_last=True
Seleciona "Authorization" -> "Custom"
E escreve Token meutoken

Uma vez sabendo que a chamada estava funcionando, URL, Token e Header estavam corretos, ficou mais fácil arrumar meu programa.

@brunoorosco

This comment has been minimized.

Copy link

@brunoorosco brunoorosco commented Nov 20, 2020

@nativow e @giuliano-oliveira, perfeitamente os dois trechos de código estão funcionando perfeitamente. Obrigado pela colaboração.

@elsonss1988

This comment has been minimized.

Copy link

@elsonss1988 elsonss1988 commented Nov 24, 2020

Muito Obrigado pelo o Help, @nativow, não conhecia esse site, mas sensancional, muito bom para validar.

Fizemos um teste e funcionou com o trecho abaixo.

var ApiLink = "https://api.brasil.io/v1/dataset/genero-nomes/nomes/data?first_name=" + first_name + "&format=json";
$.ajax({
url: ApiLink,
method: 'GET',
async: true,
headers: { Authorization: Token ${token}},
...

Muito obrigado @todos.

@lucaspgg3

This comment has been minimized.

Copy link

@lucaspgg3 lucaspgg3 commented Nov 26, 2020

Estou usando a biblioteca Papa Parse no JavaScript para baixar os dataset com filtros em formato CSV e depois fazer a leitura dos dados. Estava funcionando perfeitamente até a implementação da autenticação com o token ser adicionada também ao download dos arquivos. Fiz vários testes tentando passar o token no cabeçalho, me inspirando nas orientações que constam na documentação da biblioteca, aqui. Meu código ficou assim, mas ainda não consigo autenticar corretamente e receber o arquivo como eu recebia antes:

function loadInfoEstados() {
    Papa.parse("https://brasil.io/dataset/covid19/caso_full/?place_type=city&is_last=True&is_repeated=False&format=csv", {
        header: true,
        download: true,
        dynamicTyping: true,
        downloadRequestHeaders: {
            'Authorization': 'token 0123345678901234567890',
        },
        complete: function(results) {
            var estrutura = results.data;
            estadosJSON(estrutura);
            id = "estado";
        }
    });
}

Alguém passou por uma situação parecida e conseguiu resolver?

@elsonss1988

This comment has been minimized.

Copy link

@elsonss1988 elsonss1988 commented Nov 26, 2020

@lucaspgg3 com o endereço "https://api.brasil.io/v1/dataset" ocorre o mesmo problema?

@lucaspgg3

This comment has been minimized.

Copy link

@lucaspgg3 lucaspgg3 commented Nov 26, 2020

@lucaspgg3 com o endereço "https://api.brasil.io/v1/dataset" ocorre o mesmo problema?

Sim, @elsonss1988. Dá o mesmo erro.

Na verdade, o caminho para download do arquivo CSV com o filtro é seguindo o padrão https://brasil.io/dataset/covid19/caso_full/...

Pelo os meus testes aqui, o caminho https://api.brasil.io/v1/dataset/... não retorna CSV

@turicas

This comment has been minimized.

Copy link
Owner Author

@turicas turicas commented Nov 26, 2020

Estou usando a biblioteca Papa Parse no JavaScript para baixar os dataset com filtros em formato CSV e depois fazer a leitura dos dados. Estava funcionando perfeitamente até a implementação da autenticação com o token ser adicionada também ao download dos arquivos. Fiz vários testes tentando passar o token no cabeçalho, me inspirando nas orientações que constam na documentação da biblioteca, aqui. Meu código ficou assim, mas ainda não consigo autenticar corretamente e receber o arquivo como eu recebia antes:

function loadInfoEstados() {
    Papa.parse("https://brasil.io/dataset/covid19/caso_full/?place_type=city&is_last=True&is_repeated=False&format=csv", {
        header: true,
        download: true,
        dynamicTyping: true,
        downloadRequestHeaders: {
            'Authorization': 'token 0123345678901234567890',
        },
        complete: function(results) {
            var estrutura = results.data;
            estadosJSON(estrutura);
            id = "estado";
        }
    });
}

Alguém passou por uma situação parecida e conseguiu resolver?

@fernandascovino

This comment has been minimized.

Copy link

@fernandascovino fernandascovino commented Nov 26, 2020

@turicas a função data não estava funcionando pois request não é definido. Fiz uma adaptação no código para:

(1) Utilizar nesse caso a função api_request e,
(2) Resolver a autenticação do usuário em headers (mudei o nome aqui, antes era api_headers) - adicionei uma condicional para o caso de requisição na API, e adicionei o parâmetro user_agent para autenticação:

Agora a função funcionou aqui! :D

import csv
import gzip
import io
import json
from urllib.parse import urlencode, urljoin
from urllib.request import Request, urlopen


class BrasilIO:

    base_url = "https://api.brasil.io/v1/"

    def __init__(self, user_agent=None, auth_token=None):
        """
        Caso queria fazer uma requisição na API, passe os parâmetros user_agent e auth_token.
        Para fazer somente o download do arquivo completo, não é necessário passar nenhum parâmetro.
        """
        self.__user_agent = user_agent
        self.__auth_token = auth_token

    def headers(self, api=True):
        if api:
            return {
                "User-Agent": f"{self.__user_agent}",
                "Authorization": f"Token {self.__auth_token}"
            }
        else:
            return {
                "User-Agent": "python-urllib/brasilio-client-0.1.0",
            }
            

    def api_request(self, path, query_string=None):
        url = urljoin(self.base_url, path)

        if query_string:
            url += "?" + query_string

        request = Request(url, headers=self.headers(api=True))

        response = urlopen(request)
        return json.load(response)
        
    def data(self, dataset_slug, table_name, filters=None):
        url = f"dataset/{dataset_slug}/{table_name}/data/"
        filters = filters or {}
        filters["page"] = 1

        finished = False
        while not finished:
            query_string = "&".join([f"{k}={v}" for k, v in filters.items()])
            response = self.api_request(url, query_string)
            next_page = response.get("next", None)
            for row in response["results"]:
                yield row
            filters = {}
            url = next_page
            finished = next_page is None

    def download(self, dataset, table_name):
        url = f"https://data.brasil.io/dataset/{dataset}/{table_name}.csv.gz"
        request = Request(url, headers=self.headers(api=False))
        response = urlopen(request)
        return response


if __name__ == "__main__":
    # Caso não tenha, cadastre-se no Brasil.io e gere seu Token
    # Para mais instruções: https://blog.brasil.io/2020/10/10/como-acessar-os-dados-do-brasil-io/
    user_agent = "seu-usuario"
    auth_token = "seu-token"

    api = BrasilIO(user_agent, auth_token)

    dataset_slug = "covid19"
    table_name = "caso_full"

    # Para baixar o arquivo completo:

    # Após fazer o download, você salvá-lo no disco ou percorrer o arquivo em
    # memória. Para salvá-lo no disco:
    response = api.download(dataset_slug, table_name)
    with open(f"{dataset_slug}_{table_name}.csv.gz", mode="wb") as fobj:
        fobj.write(response.read())
        # TODO: o código acima pode ser melhorado de forma a não utilizar
        # `response.read()` para não colocar todo oarquivo em memória e sim fazer
        # streaming da resposta HTTP e salvar cada chunk diretamente no `fobj`.
        
    # Caso queira percorrer o CSV em memória:
    response = api.download(dataset_slug, table_name)
    fobj = io.TextIOWrapper(gzip.GzipFile(fileobj=response), encoding="utf-8")
    reader = csv.DictReader(fobj)
    for row in reader:
        pass  # faça algo com `row`
    
    # Para navegar pela API:
    filters = {"state": "PR", "is_last": True}
    data = api.data(dataset_slug, table_name, filters)
    for row in data:
        print(row)  # faça algo com `row`
@galdir

This comment has been minimized.

Copy link

@galdir galdir commented Nov 30, 2020

boa @fernandascovino! Eu tive o mesmo problema, levei um tempo para resolver e voltei aqui para compartilhar a solução também :) 👍

@jecogeo

This comment has been minimized.

Copy link

@jecogeo jecogeo commented Dec 1, 2020

Pessoal, eu não sou fluente em Python, mas faço meus "frankensteins". Eu não estou entendendo como passar os filtros e colocar tudo em um pandas dataframe.

Antigamente eu fazia:

url = "https://brasil.io/api/dataset/covid19/caso/data?state=AM&page_size=10000"
r = requests.get(url)
data = r.json()
df = json_normalize(data['results'])

e pronto, estava em um dataframe. Como eu reproduzo esse filtro (state=AM&page_size=10000) e coloco isso em um dataframe? Fiz várias tentativas fracassadas... Se alguém puder ajudar, agradeço muito!

PS.: os estado do AM tem duas páginas, então seria bom colocar os resultados das duas no mesmo dataframe.

@prdm0

This comment has been minimized.

Copy link

@prdm0 prdm0 commented Dec 5, 2020

@turicas, Algo interessante seria disponibilizar o arquivo RData com os dados completos. Por exemplo, atualmente o arquivo disponível em https://data.brasil.io/dataset/covid19/caso_full.csv.gz com 160 MB poderia ser reduzido para 5,1 MB. É importante destacar que essa compressão é muito rápida, muito fácil de implementar e a leitura do arquivo reduzido em R ou em Python também é muito rápida. A redução do tamanho do arquivo é mais de 31,37 vezes, aproximadamente.

Uma vez que foi declarado da grande possibilidade de bloqueios de IPs ou mesmo da não disponibilização da API diante dos excessos ("abusos"), penso que disponibilizar também os dados no formato RData seria algo muito útil e importante (pequeno para baixar e rápido para ler).

image

Em R, você poderá realizar a compressão com o código abaixo:

library(vroom)
library(fs)

download_save <- function(path = "~/Downloads") {
  covid19_brasil_io <-
      vroom("https://data.brasil.io/dataset/covid19/caso.csv.gz")
  save(
    file = fs::path(
      path,
      "covid19_brasil_io",
      ext = "RData"
    ),
    covid19_brasil_io,
    compress = "xz"
  )  
}

Em Python existem formas de ler arquivos RData:

import pyreadr

result = pyreadr.read_r('/path/to/file.RData') # also works for Rds

Acredito que isso seria útil, uma vez que a rede de quem estiver usando uma aplicação pode não ser de alta velocidade. Baixar um arquivo menor é algo que poderia ajudar. Além disso, a leitura do arquivo compactado é muito rápida, para o estado atual do arquivo, dura um pouco mais de 1 segundo em minha máquina:

Mensurando o tempo de leitura de um arquivo RData:

> system.time(load(file = "/home/prdm0/Downloads/covid19_brasil_io.RData"))
  usuário   sistema decorrido 
    1.162     0.000     1.163 

Mensurando melhor a leitura do arquivo RData - Benchmark:

O gráfico abaixo é um Violin Plot obtido em 100 execuções de leitura do arquivo RData com todos os dados da Covid-19 do projeto Brasil.IO, dados estes disponíveis em https://data.brasil.io/dataset/covid19/caso_full.csv.gz. Note que o tempo máximo de leitura foi de aproximadamente 2,4 segundos e o tempo mínimo um pouco acima de 1,6 segundos, com média de leitura em 2,03 segundos.

image

Isso mostra que considerar o arquivo RData pode ser uma boa ideia para todos. As vantagens de se considerar também a distribuição do formato RData são:

  1. Arquivo mais de 31 vezes menor que o arquivo disponibilizado em https://data.brasil.io/dataset/covid19/caso_full.csv.gz;
  2. É possível ler facilmente arquivos RData em R ou Python e muito provavelmente em vários outras linguagens;
  3. É muito rápido e fácil gerar o arquivo RData;
  4. É muito rápido ler o arquivo RData.

Importante: Note que é uma sugestão de um formato a mais de distribuição dos dados que poderá ser útil para muitas pessoas. Não sugiro jamais remover os outros formatos.

Dados em R:

image

Dados em Python:

Não sou programador de Python mas testei a biblioteca pyreadr e funcionou muito bem:

image

Acredito que disponibilizar o arquivo RData seria muito útil e algo muito fácil de implementar. Isso poderia abrir espaço para as pessoas desistirem de onerar a API de vocês. Isso seria uma forma de diminuir os abusos.

@kleyber-ribeiro

This comment has been minimized.

Copy link

@kleyber-ribeiro kleyber-ribeiro commented Mar 5, 2021

@turicas, eu cadastrei 2 tokens de acesso, estou usando PHP para acessar via cURL a API, para pegar dados apenas 1x ao dia, mas não consigo acessar... me dá o erro 401... não quero onerar de forma alguma a API de vocês, mas não vou poder buscar as informações 1x ao dia? Não é plausível?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment