Files
TextNLPClassifierApp/specs/002-google-news-extractor/spec.md
T
andreferraro 6e3d57619b feat(extractor): add Google News headlines extractor with Foxcape headless and URL resolution
- Add standalone CLI script scripts/extract_google_news.py for Google News RSS scraping
- Integrate foxcape in headless mode as primary stealth anti-bot engine
- Implement parallel article URL resolution using googlenewsdecoder and ThreadPoolExecutor
- Support language and regional locale mapping (-l, --lang, --locale)
- Implement real-time progress logging in stderr and --silent flag
- Add unit, integration, and live E2E tests in tests/test_extract_google_news.py
- Add full SpecKit documentation (specs/002-google-news-extractor/)
- Create comprehensive README.md covering both NLP Classifier and Google News Extractor
2026-08-20 11:50:16 -03:00

7.3 KiB

Feature Specification: Google News Headlines Extractor

Feature Branch: 002-google-news-extractor
Created: 2026-08-20
Status: Implemented & Validated
Input: User description: "Extrator de manchetes do Google News de acordo com assunto, idioma, locale, com Foxcape headless, resolução de URLs reais e logging"


Clarifications

Session 2026-08-20

  • Q: Como o extrator de notícias do Google News deve ser disponibilizado e consumido dentro do projeto? → A: Apenas Script CLI autônomo para execução direta via linha de comando no terminal (scripts/extract_google_news.py).
  • Q: Qual biblioteca/mecanismo de requisição e raspagem deve ser utilizado no script CLI? → A: Biblioteca foxcape (https://pypi.org/project/foxcape/) em modo headless=True com proteção anti-bot e fingerprinting stealth.
  • Q: Como lidar com as URLs intermediárias do Google News? → A: Resolução e decodificação automática das URLs intermediárias (https://news.google.com/rss/articles/...) para as URLs reais e finais dos portais de notícias via googlenewsdecoder.
  • Q: Como acompanhar o progresso de extração no terminal? → A: Logs informativos em tempo real enviados exclusivamente para sys.stderr, mantendo sys.stdout limpo para pipes JSON e suportando a flag -s / --silent.

User Scenarios & Testing (mandatory)

User Story 1 - Extração Básica de Notícias com URLs Finais Resolvidas (Priority: P1) 🌟 MVP

Como analista ou operador no terminal, quero fornecer um termo de busca e um idioma de interesse via linha de comando para obter rapidamente uma lista estruturada de manchetes recentes com as URLs finais reais dos veículos de imprensa (ex: Olé, TyC Sports, ge, ESPN).

Why this priority: É o valor fundamental do produto. Sem a capacidade de buscar, obter manchetes e fornecer os links diretos dos veículos, o extrator não cumpre sua função de pesquisa e ingestão.

Independent Test: Executar python scripts/extract_google_news.py -q "River Plate" -l es --locale AR -p 1 e verificar se o JSON retornado contém notícias com URLs apontando para os domínios finais (tycsports.com, ole.com.ar, etc.).

Acceptance Scenarios:

  1. Given um termo de busca válido e idioma, When o script for executado com o motor foxcape em modo headless, Then o sistema extrai o feed RSS e decodifica as URLs de cada artigo para os sites de origem.
  2. Given um termo de busca sem notícias correspondentes, When o script for executado, Then o sistema retorna uma coleção vazia com código de saída 0.

User Story 2 - Filtragem Regional e Edição Geográfica (Priority: P2)

Como usuário que monitora notícias em mercados específicos, quero definir a região/país geográfica (locale) além do idioma (por exemplo, espanhol da Argentina --locale AR vs. México --locale MX, ou inglês do Reino Unido --locale GB vs. Estados Unidos --locale US) para receber manchetes contextualmente relevantes àquele território.

Why this priority: Garante relevância e precisão geográfica para análises de mídia multinacionais e segmentadas.

Independent Test: Executar o script com idioma "es" e locale "AR" e verificar que portais e manchetes são da Argentina.

Acceptance Scenarios:

  1. Given um termo de busca, idioma "es" e país/região "AR", When o script CLI for executado, Then as manchetes retornadas priorizam a edição e veículos argentinos.
  2. Given um idioma informado sem país explícito (ex: "pt"), When o script for solicitado, Then o sistema aplica o mapeamento padrão correspondente (ex: Brasil / pt-BR).

User Story 3 - Paginação, Exportação em Arquivo e Feedback Visual (Priority: P3)

Como operador de automação de dados, quero parametrizar o número de páginas de resultados (--max-pages 1..10), exportar direto para arquivo (--output) e acompanhar o progresso no terminal com mensagens descritivas de log.

Why this priority: Permite flexibilidade de uso em rotinas batch, pipelines de ETL e depuração interativa.

Independent Test: Executar com -p 2 -o out/resultado.json e verificar criação do arquivo com diretórios pais automáticos e logs em stderr.

Acceptance Scenarios:

  1. Given uma execução CLI com -p 2 -o out/teste.json, When o processo é executado, Then o terminal exibe logs em stderr ([INFO] 🔍 Consultando..., [INFO] 🔗 Decodificando..., [INFO] 💾 Arquivo salvo...) e grava o JSON final com 20 itens.
  2. Given o uso da flag -s ou --silent, When o script é executado, Then os logs em stderr são suprimidos.

Edge Cases

  • Termo de busca vazio ou composto apenas por espaços: O script rejeita a solicitação com mensagem de erro em stderr e código de saída 1.
  • Falha de conectividade ou bloqueio: O Foxcape executa com evasões anti-bot em modo headless, com captura de exceções e emissão de erro em stderr com código de saída 2.
  • Resumo da notícia idêntico ao título: Subtítulo redundante vira None.
  • Caminho de saída em pasta inexistente: O script cria os diretórios pais automaticamente antes de salvar.
  • Falha na decodificação de URL específica: Mantém a URL original como fallback gracioso sem abortar a execução dos demais itens.

Requirements (mandatory)

Functional Requirements

  • FR-001: O sistema DEVE ser disponibilizado como script CLI autônomo em scripts/extract_google_news.py.
  • FR-002: O script DEVE utilizar a biblioteca foxcape com FoxcapeConfig(headless=True) como motor primário de requisição com proteção anti-bot.
  • FR-003: O CLI DEVE aceitar argumento obrigatório para o termo de busca (-q, --query, --keyword).
  • FR-004: O CLI DEVE suportar argumentos opcionais para código de idioma (-l, --lang, --language, padrão pt) e região/país (--locale, --country).
  • FR-005: O sistema DEVE aplicar mapeamento padrão de região quando apenas o idioma for informado (pt → BR, es → AR, en → US, de → DE, fr → FR, it → IT).
  • FR-006: O CLI DEVE permitir configurar a paginação lógica (-p, --max-pages, de 1 a 10 páginas / 10 a 100 itens).
  • FR-007: O sistema DEVE extrair: título, URL, data de publicação, subtítulo higienizado de HTML e número da página.
  • FR-008: O sistema DEVE resolver e decodificar automaticamente as URLs intermediárias do Google News para as URLs finais dos portais de notícias em paralelo.
  • FR-009: O CLI DEVE emitir logs informativos de progresso em sys.stderr e suportar a flag -s, --silent para supressão.
  • FR-010: O CLI DEVE suportar a flag --no-resolve-urls para obter as URLs brutas do feed RSS quando desejado.
  • FR-011: O CLI DEVE suportar gravação em arquivo via -o, --output com criação de diretórios pais e formatação legível com --pretty.

Success Criteria (mandatory)

  • SC-001: Extração executada com sucesso utilizando Foxcape headless e alta taxa de entrega.
  • SC-002: 100% das URLs de notícias decodificadas para os portais reais dos veículos quando a resolução de URLs estiver ativa.
  • SC-003: 100% dos resumos/subtítulos livres de marcações HTML.
  • SC-004: Formato JSON no stdout 100% compatível com utilitários como jq e pipelines shell.
  • SC-005: 100% dos testes unitários e E2E aprovados no pytest.