- 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
48 lines
3.5 KiB
Markdown
48 lines
3.5 KiB
Markdown
# Research: Google News Headlines Extractor
|
|
|
|
## 1. Technical Decisions & Tradeoffs
|
|
|
|
### Decision 1: Motor de Requisição e Scraping com `foxcape` em Modo Headless
|
|
- **Decision**: Adotar o pacote `foxcape` com `FoxcapeConfig(headless=True, humanize=False)` como motor de requisição primário.
|
|
- **Rationale**: `foxcape` integra Camoufox e BeautifulSoup com evasões de fingerprinting TLS, runtime JS e headers avançados, impedindo bloqueios (429/403/Captchas) frequentes do Google News. A configuração `headless=True` garante que a execução ocorra 100% em segundo plano sem abrir janelas gráficas no sistema.
|
|
- **Alternatives Considered**:
|
|
- `curl_cffi` + `beautifulsoup4` manual: Boa alternativa, mas exige orquestração manual de impersonação de TLS e headers.
|
|
- `requests` padrão: Alto risco de bloqueio anti-bot pelo Google News.
|
|
- Foxcape padrão sem configuração (`headless=False`): Abre janela visual do Firefox indesejada em execuções CLI e servidores.
|
|
|
|
---
|
|
|
|
### Decision 2: Endpoint RSS do Google News vs. Scraping de DOM
|
|
- **Decision**: Utilizar o endpoint oficial de busca RSS do Google News: `https://news.google.com/rss/search?q={query}&hl={hl}&gl={gl}&ceid={gl}:{hl}`.
|
|
- **Rationale**: Formato estruturado em XML padrão, com carregamento rápido e direto de todos os metadados necessários (`title`, `link`, `pubDate`, `description`), sem necessidade de lidar com seletores CSS voláteis da interface web renderizada.
|
|
- **Alternatives Considered**:
|
|
- Scraping direto da interface HTML do Google News (`news.google.com/search`): Classes CSS ofuscadas e alteradas frequentemente pelo Google, quebrando facilmente a extração.
|
|
|
|
---
|
|
|
|
### Decision 3: Mapeamento de Idioma e Locale (`hl`, `gl`, `ceid`)
|
|
- **Decision**: Tabela de mapeamento determinística com fallback dinâmico.
|
|
- `pt` → `hl=pt-BR`, `gl=BR`, `ceid=BR:pt-BR`
|
|
- `es` → `hl=es-419`, `gl=AR`, `ceid=AR:es-419`
|
|
- `en` → `hl=en-US`, `gl=US`, `ceid=US:en-US`
|
|
- `de` → `hl=de`, `gl=DE`, `ceid=DE:de`
|
|
- `fr` → `hl=fr`, `gl=FR`, `ceid=FR:fr`
|
|
- `it` → `hl=it`, `gl=IT`, `ceid=IT:it`
|
|
- Customizado: se fornecido `--locale MX`, sobrescreve o `gl` e ajusta `ceid={gl}:{hl}`.
|
|
- **Rationale**: Garante notícias contextualmente adequadas por país sem que o usuário precise memorizar os códigos técnicos internos do Google News.
|
|
|
|
---
|
|
|
|
### Decision 4: Resolução de URLs do Google News via `googlenewsdecoder`
|
|
- **Decision**: Resolver automaticamente as URLs intermediárias (`news.google.com/rss/articles/CBMi...`) para os links originais dos veículos de imprensa em lote com `concurrent.futures.ThreadPoolExecutor(max_workers=5)`.
|
|
- **Rationale**: Os links gerados pelo Google News contêm tokens RPC intermediários que dificultam a leitura e ingestão direta. A decodificação em lote resolve até 50 URLs em menos de 1 segundo sem sobrecarga.
|
|
- **Alternatives Considered**:
|
|
- Resolução via Playwright headless para cada link: Muito lenta para listas de 20 a 50 notícias (demora 30 a 60 segundos).
|
|
- Manter apenas a URL do Google News: Prejudica o usuário e sistemas downstream que precisam do domínio e link real do portal de notícias.
|
|
|
|
---
|
|
|
|
### Decision 5: Logging em Tempo Real no `stderr` e Segregação de Streams
|
|
- **Decision**: Enviar mensagens de status (`[INFO] ...`) para `sys.stderr` e reservar `sys.stdout` exclusivamente para o JSON.
|
|
- **Rationale**: Permite que o operador acompanhe o progresso em tempo real no terminal (`Consultando...`, `Decodificando URLs...`, `Arquivo salvo...`) sem quebrar a interoperabilidade com ferramentas de pipe como `jq` ou redirecionamentos de arquivo.
|