import juscraper as jus
# `max_captcha_attempts` retries from a fresh form on each captcha rejection.
trf6 = jus.scraper("trf6", max_captcha_attempts=5)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
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 |