Projeto pessoal/Registro de andamento/2026-08-13

INPI Patent Tracker

Pipeline de dados de patentes do INPI — depósito, publicação, despachos e anuidades — tratado e normalizado para responder perguntas de BI sobre tramitação processual. Recorte atual: pedidos depositados de 2010-01-01 até hoje, sem filtro de depositante ou IPC.

461.159processos no recorte
128.921depositantes resolvidos
2.515.946despachos catalogados
500 / 461.159anuidades coletadas

Fases do projeto0 → 7

0

Spike de viabilidade

Concluído

Testado antes de escrever qualquer pipeline: o que o portal de dados abertos cobre, e se a extranet permite automação.

  • Portal de dados abertos cobre quase tudo: bibliográficos, IPC, depositantes (com CPF/CNPJ), despachos, inventores, procuradores, prioridades.
  • Único gap: anuidades — só existem na extranet.
  • Extranet sem captcha em busca anônima; tabela oficial de códigos de despacho existe em PDF pronto pra parsear.
1

Escopo do recorte

Concluído

Expandido em 2026-08-13 de "últimos 3 anos" pra 2010-01-01 até hoje (2010-01-01 a 2026-08-12), sem filtro de depositante ou IPC — 8,2x mais processos (56.329 → 461.159), quase 20x mais despachos (128.077 → 2.515.946), já que processos mais antigos tiveram mais tempo de acumular despacho.

2

Scraper de anuidade

Confiável, rodando aos poucos

Reescrito via Selenium replicando o fluxo de clique real (busca → resultado → modal de anuidades) — a causa do "endpoint vazio" nunca foi bot detection, era o servidor só liberar o detalhe depois da busca ser submetida naquela sessão. Lote de validação em escala: 499/500 processos, 1 erro (99,8%), ~4h19min headless, sem degradação ao longo do lote.

  • CodPedido é o codigo_interno dos dados abertos, mas numero_pedido (o que se digita na busca) é outro campo — precisa dos dois.
  • Restart periódico do ChromeDriver a cada N buscas eliminou a degradação de sessão que aparecia em lotes longos.
  • Métricas por etapa (bootstrap, clique, modal...) logadas em JSONL — dá pra analisar onde o tempo vai.
500 de 461.159 processos raspados até agora (0,1%, recorte expandido pra 2010+). No ritmo confirmado em escala, cobrir o recorte inteiro levaria meses rodando headless continuamente — coleta gradual e indefinida, não um objetivo de curto prazo.
3

ETL bronze → silver → gold

Concluído

Download dos 9 CSVs de dados abertos (~1,9 GB), filtro pelo recorte via semi-join por codigo_interno, montagem do modelo estrela.

4

Entity resolution

Concluído

Depositante resolvido por raiz de CNPJ (8 dígitos, agrupa filiais) quando disponível; senão por nome normalizado (acento + pontuação removidos).

Limitação conhecida: aliases genuinamente diferentes pra mesma entidade estrangeira (ex: duas grafias distintas do mesmo instituto) continuam separados — precisaria de fuzzy matching de verdade.
5

Modelo estrela

Concluído

dim_processo, dim_depositante, fato_processo_depositante, fato_despacho e agora fato_anuidade (166 processos) prontos em data/gold/, mais um banco DuckDB persistente (inpi.duckdb) com views e macros parametrizadas.

6

Orquestração (Airflow)

Concluído

Docker Desktop instalado (via winget, sem reiniciar), Airflow 3.3.1 rodando via docker-compose com LocalExecutor. DAG completo (download → bronze → silver → gold → validate) testado ao vivo — passou ponta a ponta em ~16s.

7

BI

Dashboard interativo publicado

Dois painéis calculam ao vivo: "tempo entre despacho X e Y" (com filtro opcional de depositante) e "quantos casos do depositante F tiveram despacho Z na janela T" — pra qualquer código/nome/data. Reescrito pra DuckDB-WASM (SQL de verdade, rodando no navegador) depois que a expansão do recorte pra 2010+ estourou o limite de embutir os dados brutos na página (2,5 milhões de despachos = 60MB de JSON). Dados em parquet comprimido (~13MB) servidos separado do HTML.

Achados durante a validação7 registros

ENC-1
corrigido
CNPJ completo fragmentava instituições por filial

USP virava 2 depositantes, EMBRAPA virava 5. Corrigido agrupando pela raiz do CNPJ (8 dígitos).

ENC-2
corrigido
Placeholder "estrangeiro" tratado como CNPJ único

8.873 empresas estrangeiras diferentes colapsaram num único depositante fictício de 29 mil processos. Corrigido: só dígitos puros contam como identificador.

ENC-3
corrigido
Acentuação inconsistente na fonte duplicava entidades

INSERM (instituto francês) aparecia como 3 depositantes por variação de encoding no nome. Corrigido com normalização de acento e pontuação.

ENC-4
corrigido
sigiloso nulo em vez de falso

WHERE NOT sigiloso filtrava a tabela inteira — NULL não é TRUE em SQL de três valores. Corrigido com coalesce(..., false).

ENC-5
corrigido
Totais de BI inflados por co-depositante

As views de tempo/contagem agrupam por depositante — somar qtd_processos pra achar um total geral conta processos com múltiplos depositantes várias vezes. 7.1→9.2 tinha sido reportado como 1.284 processos; o real (por codigo_interno) é 282. Corrigido com macros que contam por processo.

ENC-6
corrigido
"Endpoint vazio" não era bot detection

Testado requests, Playwright (headless/headed/anti-detecção) e undetected-chromedriver — todos vazios. Causa real: o servidor só libera Action=detail depois da busca ser submetida naquela sessão. Resolvido replicando o fluxo de clique completo via Selenium comum.

ENC-7
corrigido
Dashboard não escala embutindo dados brutos

Expandir o recorte pra 2010+ (2,5 milhões de despachos) estourou o limite de 16MB do artifact (JSON bruto viraria 60MB). DuckDB-WASM resolveria, mas o binário sozinho (34-41MB) passa até do limite de 25MB por arquivo do Cloudflare Pages. Solução: motor via jsDelivr (CDN pública do próprio pacote npm — a recomendação padrão da lib), só os dados (parquet comprimido, ~13MB) hospedados no Pages.

Próximos passos

Continuar a coleta gradual de anuidade

500 de 461.159 (0,1%) até agora, ritmo confiável (~22-30s/processo, 99,8% de sucesso no último lote de 500). Coleta contínua de longo prazo, não uma meta de curto prazo — o recorte cresceu 8x com a expansão pra 2010+.

Investigar status de anuidade malformado

13 de 606 registros (2,1%) vieram com status "Tipo: Anuidade" em vez do status real — bug pontual de parsing a rastrear em process_detail.py.

Expandir o dashboard

Agora em inpi-patent-tracker.pages.dev com DuckDB-WASM (SQL de verdade, recorte completo de 2010+). O artifact do claude.ai continua existindo mas não acompanha mais essa versão pesada — 89MB não cabe no limite de 16MB. Considerar Metabase de verdade se as perguntas ad-hoc crescerem além do que os dois painéis cobrem.