You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hoje camara.py e senado.py fazem HTML scraping das páginas de busca dos respectivos sites:
camara.py: HTML scraping de https://www.camara.leg.br/legislacao/busca — retorna 4 campos (link, titulo, descricao, ementa).
senado.py: HTML scraping de https://www6g.senado.leg.br/busca — retorna 5 campos.
Ambos aceitam apenas pesquisa, ano, tipo_materia.
Isso é frágil (quebra a cada mudança de layout) e expõe pouquíssimo do que as APIs oficiais oferecem. Esta issue substitui parte da #27 e propõe uma reescrita ambiciosa: wrapper completo das APIs oficiais, mantendo raspar(pesquisa=...) compatível.
Objetivo
Migrar camara.py e senado.py para consumir as APIs oficiais, com:
Cliente HTTP compartilhado com cache local, retry, rate limit e suporte async opcional.
Sessão única (`requests.Session`) com adapter configurado.
Cache local com `requests-cache` (SQLite em diretório do usuário; TTL por endpoint — `referencias` cacheia mais tempo, dados ao vivo cacheiam menos).
Retry com backoff exponencial em 429/5xx respeitando `Retry-After` (refatorar a lógica de `base_scraper.py`, hoje orientada à paginação, para ser reusável aqui via `HTTPAdapter` + `urllib3.Retry`).
Rate limit configurável (default ~1 req/s) — falta no projeto hoje.
Async opcional com `httpx.AsyncClient` para varrer 513 deputados em paralelo.
Senado: normalização XML→dict (via `xmltodict`) ou parsing dos endpoints `.json` corrigindo as chaves estranhas (`@xml:lang`, listas-de-um-elemento que viram dict, etc.).
Implementar `senado_api/{senadores,materias,votacoes,comissoes,plenario,processo,orcamento,agencia,reuniao,lista,autoria}.py` com normalização XML.
Refatorar `camara.py` e `senado.py` para usar o novo cliente, mantendo `raspar()` compatível e adicionando filtros novos.
Implementar `camara_api/bulk.py` (download de CSVs anuais).
Implementar `*_api/joins.py` (helpers de composição).
Adicionar `tests/test_camara.py` e `tests/test_senado.py` com mocks (`responses` ou `vcrpy`). Cobrir: paginação, retry em 429, cache hit, normalização XML do Senado, modo legado `raspar(pesquisa=...)`, sub-recursos.
Adicionar notebook `notebooks/dev/camara_senado_master_blaster.ipynb` demonstrando: (1) modo legado preservado; (2) listar deputados por legislatura/UF; (3) despesas de cota parlamentar; (4) proposições por autor + filtro de data; (5) votação completa (orientações + votos); (6) bulk download de um ano de votações; (7) buscar matérias do Senado por assunto; (8) composição de uma comissão.
DadosAbertosBrasil (Python, v2.0.1 ago/2025, ativo) — referência principal. Modelo de classes-domínio (`Deputado`, `Proposicao`, `Senador`, ...), parâmetro `formato="pandas"|"json"|"url"`, filtros `contendo`/`excluindo` por substring, validação Pydantic. Não tem cache, retry, rate limit, async, CLI nem joins — é exatamente onde podemos somar.
camaraPy (Python, API legada XML) — fallback para casos não cobertos pela API v2 (votações antigas).
congressbr (R) — cobertura mais completa de Senado existente. Usar a lista de funções `sen_`/`cham_` como roteiro de exaustividade ao implementar `senado_api/`. Paper: https://doi.org/10.25222/larr.447
rcongresso (R) — Câmara API v2, tibbles tidyverse, padrão `fetch_*`.
cepesp-python (TSE) — referência de cache local interno.
Contexto
Hoje
camara.pyesenado.pyfazem HTML scraping das páginas de busca dos respectivos sites:camara.py: HTML scraping dehttps://www.camara.leg.br/legislacao/busca— retorna 4 campos (link,titulo,descricao,ementa).senado.py: HTML scraping dehttps://www6g.senado.leg.br/busca— retorna 5 campos.pesquisa,ano,tipo_materia.Isso é frágil (quebra a cada mudança de layout) e expõe pouquíssimo do que as APIs oficiais oferecem. Esta issue substitui parte da #27 e propõe uma reescrita ambiciosa: wrapper completo das APIs oficiais, mantendo
raspar(pesquisa=...)compatível.Objetivo
Migrar
camara.pyesenado.pypara consumir as APIs oficiais, com:APIs oficiais
Estrutura proposta
```
src/raspe/scrapers/
├── camara.py # mantém ScraperCamaraDeputados (compat raspar()) + delega para módulo
├── senado.py # mantém ScraperSenadoFederal (compat raspar()) + delega para módulo
├── camara_api/
│ ├── init.py # exporta classes-domínio
│ ├── client.py # cliente HTTP com cache, retry, rate limit
│ ├── deputados.py # Deputado, lista_deputados()
│ ├── proposicoes.py # Proposicao, lista_proposicoes()
│ ├── votacoes.py
│ ├── eventos.py, frentes.py, orgaos.py, blocos.py, partidos.py, legislaturas.py
│ ├── referencias.py
│ ├── bulk.py # download dos CSVs anuais
│ └── joins.py # proposicao_completa(), deputado_completo()
└── senado_api/
├── init.py
├── client.py # cliente com normalização XML→dict
├── senadores.py
├── materias.py
├── votacoes.py, comissoes.py, plenario.py, processo.py, orcamento.py, agencia.py, reuniao.py, lista.py, autoria.py
└── joins.py
```
Cliente HTTP compartilhado (`*_api/client.py`)
Modos de uso (compatibilidade preservada)
```python
import raspe
Modo legado (continua funcionando)
camara = raspe.camara()
df = camara.raspar(pesquisa="educação", ano=2024)
Novo modo (sub-recursos)
deputados = raspe.camara.deputados.lista(legislatura=57, sigla_uf="SP")
prop = raspe.camara.proposicoes.get(2390524)
df = prop.tramitacoes(formato="pandas")
Bulk
raspe.camara.bulk.cotas(ano=2024).to_parquet("cotas_2024.parquet")
Joins
completa = raspe.camara.joins.proposicao_completa(2390524) # autor + tramitação + votações + temas
```
Filtros adicionais nos `raspar()` (acréscimo, sem quebra)
Sub-tasks
Bibliotecas pesquisadas (do que copiar)
Não faz parte desta issue
Supersedes #27.