Files

124 lines
3.9 KiB
Markdown

# CLI Contract & Routing Specification: `scripts/extract_article_contents.py`
## 1. Interface de Linha de Comando (CLI)
O script `scripts/extract_article_contents.py` preserva 100% da interface CLI existente sem novos argumentos:
```bash
python scripts/extract_article_contents.py \
-i, --input PATH # (Obrigatório) JSON de busca de notícias de entrada
[-o, --output PATH] # (Opcional) Caminho do JSON de saída textual
[-l, --limit N] # (Opcional) Limite máximo de artigos a processar
[--lang, --language CODE] # (Opcional) Código do idioma para NLP (ex: pt, es, en)
[-t, --timeout SEC] # (Opcional) Timeout em segundos para navegação (default: 30)
[-s, --silent] # (Opcional) Suprime logs no stderr
```
---
## 2. Regras de Resolução de Arquivos de Saída
### Caso A: Sem `-o/--output` (Padrão)
Para uma entrada: `out/river_plate.json`
- **Saída Textual**: `out/river_plate_extracted.json`
- **Saída de Mídia**: `out/river_plate_media.json` (gerado obrigatoriamente; contém `{"articles": []}` se nenhuma mídia for identificada)
### Caso B: Com `-o/--output` customizado
Para uma entrada: `out/noticias.json` com `-o out/processados/brasil_completo.json`
- **Saída Textual**: `out/processados/brasil_completo.json`
- **Saída de Mídia**: `out/processados/brasil_completo_media.json` (gerado obrigatoriamente; contém `{"articles": []}` se nenhuma mídia for identificada)
Regra:
- Diretório: mesmo diretório da saída textual informada.
- Nome base (stem): mesmo stem da saída textual informada.
- Sufixo: `_media`.
- Extensão: `.json`.
- Geração: O arquivo `*_media.json` MUST ser gerado em toda execução bem-sucedida do lote, sem omissão condicional.
---
## 3. Estrutura do Arquivo de Saída Textual (`*_extracted.json`)
```json
{
"source_file": "out/river_plate.json",
"processed_at": "2026-08-24T20:30:00.000000+00:00",
"total_articles": 8,
"successful_articles": 7,
"failed_articles": 1,
"articles": [
{
"input_meta": {
"titulo": "Notícia textual completa",
"url": "https://example.com/noticia-1",
"subtitulo": "Subtítulo",
"quando_publicado": "há 2 horas",
"pagina": 1
},
"extraction_status": "success",
"error_message": null,
"crawled_url": "https://example.com/noticia-1",
"page_title": "Título no DOM",
"http_status": 200,
"trafilatura": { "text": "...", "markdown": "...", "title": "..." },
"newspaper4k": { "text": "...", "summary": "...", "keywords": [] },
"readability": { "cleaned_text": "...", "cleaned_html": "..." }
},
{
"input_meta": {
"titulo": "Notícia onde todos provedores falharam",
"url": "https://example.com/falha"
},
"classification_status": "failed",
"error_message": "media classification providers unavailable",
"crawled_url": "https://example.com/falha",
"page_title": null,
"http_status": null,
"trafilatura": null,
"newspaper4k": null,
"readability": null
}
]
}
```
---
## 4. Estrutura do Arquivo de Saída de Mídia (`*_media.json`)
```json
{
"articles": [
{
"input_meta": {
"titulo": "Vídeo dos melhores momentos do jogo",
"url": "https://example.com/video-gols",
"subtitulo": "Assista ao lance",
"quando_publicado": "há 1 hora",
"pagina": 1
},
"crawled_url": "https://example.com/video-gols",
"page_title": "Vídeo dos Melhores Momentos",
"http_status": 200,
"content_type": "media",
"media_type": "video"
}
]
}
```
---
## 5. Códigos de Saída (Exit Codes)
| Exit Code | Significado |
|:---|:---|
| `0` | Lote processado com sucesso (arquivos gravados) |
| `1` | Arquivo de entrada inexistente ou erro de argumentos CLI |
| `2` | Erro fatal não tratado |
| `130` | Interrupção pelo usuário (`SIGINT` / Ctrl+C) |