TRF6 — Tribunal Regional Federal da 6ª Região

Public process consultation (cpopg) for the federal courts of Minas Gerais (Seção Judiciária de MG), via the eproc system at eproc1g.trf6.jus.br/eproc/.

The form is gated by a text-based image captcha that the backend does validate; we solve it via the txtcaptcha package (HuggingFace pretrained CRNN, downloaded on first call). Each captcha is bound to the session cookie, so a wrong solve triggers a fresh form fetch + new captcha — controlled by the max_captcha_attempts constructor parameter (default 3).

Feature Available
cpopg Yes
cposg No
cjsg No
cjpg No

Looking up a single process

import juscraper as jus

# `max_captcha_attempts` retries from a fresh form on each captcha rejection.
trf6 = jus.scraper("trf6", max_captcha_attempts=5)
df = trf6.cpopg("1005229-55.2023.4.06.3801")
print(df.shape)
df[["id_cnj", "processo", "classe", "data_autuacao"]]
TRF6 cpopg:   0%|          | 0/1 [00:00<?, ?it/s]Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.
TRF6 cpopg: 100%|██████████| 1/1 [00:05<00:00,  5.21s/it]TRF6 cpopg: 100%|██████████| 1/1 [00:05<00:00,  5.21s/it]
(1, 13)
id_cnj processo classe data_autuacao
0 10052295520234063801 1005229-55.2023.4.06.3801 Procedimento Comum (Vara Cível) 12/04/2023 15:07:33

Available columns

df.columns.tolist()
['processo',
 'data_autuacao',
 'situacao',
 'magistrado',
 'classe',
 'orgao_julgador',
 'assuntos',
 'polo_ativo',
 'polo_passivo',
 'mpf',
 'perito',
 'movimentacoes',
 'id_cnj']

The first six columns are the canonical scalars from the “Capa do Processo” panel. The trailing five (assuntos, polo_ativo, polo_passivo, mpf, perito, movimentacoes) are list-typed and carry the nested arrays from the rest of the detail page.

Inspecting movements

movs = df.iloc[0]["movimentacoes"]
print(f"{len(movs)} events recorded")
for m in movs[:5]:
    print(f"  {m['evento']:>3} | {m['data_hora']} | {m['descricao'][:60]}")
10 events recorded
   99 | 14/04/2026 01:29:31 | Decorrido prazo - Refer. ao Evento: 96
   98 | 05/04/2026 23:59:59 | Confirmada a intimação eletrônica - Refer. ao Evento: 96 - C
   97 | 02/04/2026 23:59:59 | Confirmada a intimação eletrônica - Refer. ao Evento: 92 - C
   96 | 26/03/2026 09:58:02 | Expedida/certificada a intimação eletrônica - Contrarrazões 
   95 | 26/03/2026 09:58:02 | EMBARGOS DE DECLARAÇÃO - Refer. ao Evento: 91

Inspecting parties

print("Polo ativo:")
for p in df.iloc[0]["polo_ativo"]:
    print(f"  - {p['descricao'][:120]}")

print()
print("Polo passivo:")
for p in df.iloc[0]["polo_passivo"]:
    print(f"  - {p['descricao'][:120]}")
Polo ativo:
  - - SANDRA MARCIA TOSTES (017.**********) | ALESSANDRA APARECIDA ESTEVAO SOARES MG142599

Polo passivo:
  - - INSTITUTO NACIONAL DO SEGURO SOCIAL (29.9**************) | SUBPROCURADORIA REGIONAL FEDERAL DA 6 REGIÃO SUBPRF6

Looking up multiple processes at once

Each lookup is one full request flow (form → captcha → search), so batches are sequential — expect ~3–5 seconds per CNJ depending on captcha-solve latency. Use sleep_time (default 1.0s) to throttle between calls.

cnjs = [
    "10052295520234063801",
    "10052379620234063812",
]
df_batch = trf6.cpopg(cnjs)
df_batch[["id_cnj", "processo", "classe"]]
TRF6 cpopg:   0%|          | 0/2 [00:00<?, ?it/s]TRF6 cpopg:  50%|█████     | 1/2 [00:01<00:01,  1.70s/it]TRF6 cpopg: 100%|██████████| 2/2 [00:02<00:00,  1.23s/it]TRF6 cpopg: 100%|██████████| 2/2 [00:02<00:00,  1.30s/it]
id_cnj processo classe
0 10052295520234063801 1005229-55.2023.4.06.3801 Procedimento Comum (Vara Cível)
1 10052379620234063812 1005237-96.2023.4.06.3812 Execução de Título Extrajudicial (Vara Execução)

Handling processes the public portal cannot return

When a CNJ does not surface in the public consultation (sigilo, archived, or simply not found), eproc re-serves the form silently with no error message. The scraper detects that and yields a row with only id_cnj populated — callers can still distinguish “looked up but missing” from “never tried”.

import pandas as pd

df_missing = trf6.cpopg("00000000020994060000")
print("processo:", df_missing.iloc[0].get("processo"))
print("classe:", df_missing.iloc[0].get("classe"))
TRF6 cpopg:   0%|          | 0/1 [00:00<?, ?it/s]TRF6 cpopg: 100%|██████████| 1/1 [00:00<00:00,  3.67it/s]TRF6 cpopg: 100%|██████████| 1/1 [00:00<00:00,  3.66it/s]
processo: None
classe: None

Splitting download from parse

cpopg is a thin wrapper over cpopg_download (raw HTML) + cpopg_parse (HTML → DataFrame). Splitting them is useful when you want to cache the raw HTMLs to disk before processing — relevant for TRF6 because each download spends a captcha solve.

htmls = trf6.cpopg_download("1005229-55.2023.4.06.3801")
print(f"got {len(htmls)} HTML(s), {len(htmls[0])} chars")

df_again = trf6.cpopg_parse(htmls, ["10052295520234063801"])
df_again[["id_cnj", "processo", "data_autuacao"]]
TRF6 cpopg:   0%|          | 0/1 [00:00<?, ?it/s]TRF6 cpopg: 100%|██████████| 1/1 [00:00<00:00,  1.09it/s]TRF6 cpopg: 100%|██████████| 1/1 [00:00<00:00,  1.09it/s]
got 1 HTML(s), 37871 chars
id_cnj processo data_autuacao
0 10052295520234063801 1005229-55.2023.4.06.3801 12/04/2023 15:07:33