- 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
🧠 TextNLPClassifierApp
Plataforma modular em Python para Classificação Multilíngue de Inerência de Entidades (NLP/LLM/ECP) e Extração Inteligente de Manchetes de Notícias com Evasão Anti-Bot (Google News RSS & Foxcape).
📑 Tabela de Conteúdos
- Visão Geral
- Instalação e Setup
- 1. Classificador de Conteúdo e Inerência (NLP / LLM / ECP)
- 2. Extrator de Manchetes do Google News
- Estrutura do Projeto
- Testes e Qualidade de Código
- Licença
🌟 Visão Geral
O TextNLPClassifierApp reúne ferramentas de engenharia de dados e processamento de linguagem natural:
classify.py: Motor de classificação semântica e contextual que determina o grau de aderência e inerência de um documento Markdown em relação a uma entidade alvo definida em um ECP Snapshot (Entity Context Profile).scripts/extract_google_news.py: Extrator de notícias por palavra-chave, idioma e região geográfica que utiliza o motor stealth Foxcape (em modo headless), decodificação paralela de URLs para os links reais dos portais de notícias e feedback em tempo real.
⚙️ Instalação e Setup
1. Clonar o Repositório e Criar Ambiente Virtual
git clone <URL_DO_REPOSITORIO>
cd TextNLPClassifierApp
python -m venv .venv
# Windows (PowerShell)
.venv\Scripts\Activate.ps1
# Linux/macOS
source .venv/bin/activate
2. Instalar Dependências
pip install -r requirements.txt
3. Baixar Binários do Navegador Stealth (Camoufox)
O motor Foxcape utiliza o navegador customizado Camoufox para evasão avançada de fingerprinting:
python -m camoufox fetch
1. 🧠 Classificador de Conteúdo e Inerência (NLP / LLM / ECP)
O que é e Como Funciona
O classificador avalia se um texto em Markdown trata centralmente, contextualmente ou apenas de forma superficial de uma determinada entidade alvo (ex: empresa, figura pública, clube, conceito). A entidade é descrita através de um ECP Snapshot (Entity Context Profile) contendo nomes canônicos, apelidos (aliases), âncoras temáticas, âncoras negativas e entidades de contexto relacional.
O sistema suporta nativamente 6 idiomas: Português (pt), Inglês (en), Espanhol (es), Francês (fr), Alemão (de) e Italiano (it).
Arquitetura de Classificação em 3 Tiers
flowchart TD
MD[Markdown Content] --> Pre[Pré-processamento & Detecção de Idioma]
ECP[ECP Snapshot JSON] --> Pre
Pre --> T1[Tier 1: Determinístico & Regras NLP]
T1 -- Alta Confiança --> Decision[Decisão Final JSON]
T1 -- Score Intermediário / Ambíguo --> T2{Tier 2 Habilitado?}
T2 -- Sim --> Emb[Tier 2: Similaridade Semântica / Embeddings]
T2 -- Não --> Decision
Emb -- Inconclusivo --> T3{Tier 3 Habilitado?}
T3 -- Sim --> LLM[Tier 3: LLM Inherence Adapter]
T3 -- Não --> Decision
LLM --> Decision
- Tier 1 (Determinístico / NLP Leve): Análise de frequência de termos, detecção de âncoras temáticas no primeiro terço do documento, contagem de aliases e penalização por âncoras negativas.
- Tier 2 (Vetorial / Embeddings) (Opcional:
--enable-embeddings): Projeção vetorial e cálculo de cosseno entre o perfil da entidade e os parágrafos do documento. - Tier 3 (LLM Fallback) (Opcional:
--enable-llm): Consulta a modelo de linguagem para desambiguação de casos limiares e sutilezas semânticas.
Categorias de Decisão
| Categoria | Descrição |
|---|---|
DIRECT_INHERENT |
O conteúdo é centrado e focado diretamente na entidade alvo. |
CONTEXTUAL_INHERENT |
A entidade é relevante no contexto da discussão, mesmo dividindo foco com outros temas. |
TANGENTIAL |
A entidade é mencionada apenas de passagem ou em listas ilustrativas. |
NOT_RELATED |
O conteúdo não possui relação substantiva com a entidade alvo. |
Formato do ECP Snapshot e Markdown
Exemplo de ECP Snapshot (ecp_sample.json):
{
"target_entity_id": "ent_river_plate",
"target_name": "River Plate",
"aliases": ["Club Atlético River Plate", "Millonario", "El Más Grande"],
"domain": "sports/football",
"anchors": ["Monumental", "Copa Libertadores", "Marcelo Gallardo", "Copa Sudamericana"],
"negative_anchors": ["Boca Juniors vitória", "Flamengo campeão"],
"graph_version": "1.0.0",
"related_entities": [
{
"entity_id": "ent_gallardo",
"name": "Marcelo Gallardo",
"relation_type": "manager",
"weight": 0.85,
"aliases": ["Muñeco"]
}
]
}
Exemplos de Uso CLI
# Classificação Determinística padrão (Tier 1)
python classify.py --ecp tests/fixtures/sample_ecp.json --content tests/fixtures/sample_article.md
# Salvar resultado em arquivo JSON formatado
python classify.py --ecp ecp.json --content artigo.md --output out/resultado_classificacao.json
# Habilitar camadas adicionais (Embeddings e LLM)
python classify.py --ecp ecp.json --content artigo.md --enable-embeddings --enable-llm
2. 📰 Extrator de Manchetes do Google News
O que é e Como Funciona
O script scripts/extract_google_news.py é um extrator CLI autônomo projetado para consultar o feed RSS do Google News com máxima velocidade, resiliência e integridade de dados.
Diferenciais Técnicos
- 🛡️ Foxcape Headless Anti-Bot: Utiliza o motor
foxcapecomFoxcapeConfig(headless=True)e Camoufox para evitar bloqueios 429/403 e captchas em segundo plano sem abrir navegadores visuais. - 🔗 Resolução Automática de URLs Reais: Decodifica em paralelo (
ThreadPoolExecutor) as URLs intermediárias do Google News (news.google.com/rss/articles/...) entregando diretamente o link final do portal de notícia (Olé, TyC Sports, ge, ESPN, BBC, etc.). - 🧹 Higienização de HTML: Sanitiza resumos e descrições, eliminando tags HTML residuais (
<ol>,<li>,<a>,<span>). - 📊 Logging Informativo no Terminal: Emite o status passo a passo no canal
stderrsem poluir a saída JSON emstdout(100% compatível com pipes ejq). - 🌎 Mapeamento de Idioma & Região: Mapeia automaticamente códigos regionais (
pt→BR:pt-BR,es→AR:es-419,en→US:en-US) permitindo customização com--locale.
Argumentos e Flags de Linha de Comando
| Flag | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
-q, --query, --keyword |
str |
Sim | — | Termo de pesquisa (ex: "River Plate"). |
-l, --lang, --language |
str |
Não | "pt" |
Código do idioma (pt, es, en, de, fr, it). |
--locale, --country |
str |
Não | None |
País/região editorial (BR, AR, MX, US, GB, ES). |
-p, --max-pages |
int |
Não | 1 |
Quantidade de páginas (1 a 10; cada página traz 10 itens). |
-o, --output |
str |
Não | None |
Caminho para salvar o arquivo JSON. |
--pretty |
flag |
Não | False |
Formata o JSON no terminal com indentação de 2 espaços. |
--no-resolve-urls |
flag |
Não | False |
Desativa a resolução e mantém as URLs brutas do Google News. |
-s, --silent, --quiet |
flag |
Não | False |
Suprime os logs de progresso no stderr. |
Exemplos Práticos de Uso
1. River Plate (Argentina / Espanhol / 2 Páginas / Salvar em Arquivo)
python scripts/extract_google_news.py -q "River Plate" -l es --locale AR -p 2 -o out/river_plate.json
- Saída no Terminal:
[INFO] 🔍 Consultando Google News: 'River Plate' (idioma: es, locale: AR, max_pages: 2)...
[INFO] 📥 Feed RSS recebido (162117 bytes).
[INFO] 📰 20 artigos extraídos do feed XML.
[INFO] 🔗 Decodificando 20 URLs do Google News para os portais reais...
[INFO] ✅ 20/20 URLs resolvidas com sucesso para os domínios de origem.
[INFO] 💾 Arquivo salvo com sucesso: 'out/river_plate.json' (20 notícias).
2. Cruzeiro (Brasil / Português / Formatado no Terminal)
python scripts/extract_google_news.py --query "Cruzeiro" --lang pt --locale BR --pretty
3. Fórmula 1 (Inglaterra / Inglês)
python scripts/extract_google_news.py --query "Formula 1" --lang en --locale GB --pretty
4. Filtragem com jq em Modo Silencioso
python scripts/extract_google_news.py -q "inteligência artificial" -s | jq '.items[].url'
📁 Estrutura do Projeto
TextNLPClassifierApp/
├── classify.py # CLI principal do Classificador de Inerência
├── scripts/
│ ├── __init__.py # Pacote utilitário de scripts
│ └── extract_google_news.py # CLI de Extração de Manchetes do Google News
├── src/ # Módulos centrais do classificador
│ ├── classifier.py # Orquestrador de classificação (Tier 1, 2, 3)
│ ├── models.py # Modelos de dados e esquemas (ECPSnapshot, Decision)
│ ├── preprocessor.py # Normalização de texto e detecção de idioma
│ └── adapters/ # Adaptadores opcionais de Embeddings e LLM
├── specs/ # Especificações e planos arquiteturais (Speckit)
│ ├── 001-nlp-classifier/ # Especificações do classificador
│ └── 002-google-news-extractor/ # Especificações do extrator de notícias
├── tests/ # Suíte de testes automatizados
│ ├── fixtures/ # Amostras de ECP, Markdown e XML RSS
│ ├── test_classifier.py # Testes unitários do classificador
│ └── test_extract_google_news.py # Testes unitários e testes E2E ao vivo
├── requirements.txt # Dependências do projeto
├── pyproject.toml # Configurações de ferramentas (pytest, ruff, mypy)
└── README.md # Documentação principal
🧪 Testes e Qualidade de Código
O repositório possui cobertura com testes unitários, testes de integração e testes End-to-End (E2E) com requisição de rede ao vivo:
# Executar todos os testes do projeto
pytest -v
# Executar especificamente os testes do Extrator de Notícias
pytest tests/test_extract_google_news.py -v
# Validação e correção automática de formatação com Ruff
ruff check --fix .
ruff format .
# Verificação estática de tipos com Mypy
mypy scripts/ src/
📄 Licença
Este projeto está licenciado sob os termos da licença MIT. Consulte o arquivo LICENSE para mais detalhes.