- 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
739 lines
22 KiB
JSON
739 lines
22 KiB
JSON
{
|
|
"schema_version": "ecp-nlp-poc-v1",
|
|
"profile_kind": "entity_context_profile",
|
|
"profile_status": "poc_reference",
|
|
"target_entity_id": "ecp_sao_paulo_fc",
|
|
"target_name": "São Paulo Futebol Clube",
|
|
"canonical_name": "São Paulo Futebol Clube",
|
|
"qid": "Q38568",
|
|
"entity_type": "sports_club",
|
|
"domains": [
|
|
"sports",
|
|
"football",
|
|
"brazil_football"
|
|
],
|
|
"primary_language": "pt-BR",
|
|
"languages": [
|
|
"pt-BR",
|
|
"pt"
|
|
],
|
|
"geo": {
|
|
"country": "BR",
|
|
"country_name": "Brazil",
|
|
"region": "SP",
|
|
"region_name": "São Paulo",
|
|
"city": "São Paulo"
|
|
},
|
|
"official": {
|
|
"website": "https://www.saopaulofc.net/",
|
|
"domains": [
|
|
"saopaulofc.net"
|
|
]
|
|
},
|
|
"identity": {
|
|
"short_description": "Brazilian professional football club based in São Paulo, Brazil.",
|
|
"founded_year": 1930,
|
|
"sport": "association_football",
|
|
"colors": [
|
|
"red",
|
|
"white",
|
|
"black"
|
|
],
|
|
"common_nicknames": [
|
|
"Tricolor Paulista",
|
|
"Clube da Fé",
|
|
"Soberano"
|
|
],
|
|
"home_venue": "MorumBIS",
|
|
"home_venue_aliases": [
|
|
"Morumbi",
|
|
"Estádio do Morumbi",
|
|
"Estádio Cícero Pompeu de Toledo",
|
|
"Cícero Pompeu de Toledo",
|
|
"MorumBIS"
|
|
]
|
|
},
|
|
"aliases": [
|
|
"São Paulo Futebol Clube",
|
|
"São Paulo FC",
|
|
"São Paulo F.C.",
|
|
"SPFC",
|
|
"São Paulo",
|
|
"Tricolor Paulista",
|
|
"Clube da Fé",
|
|
"Soberano"
|
|
],
|
|
"alias_rules": [
|
|
{
|
|
"value": "São Paulo Futebol Clube",
|
|
"strength": "strong",
|
|
"ambiguous": false,
|
|
"requires_context": []
|
|
},
|
|
{
|
|
"value": "São Paulo FC",
|
|
"strength": "strong",
|
|
"ambiguous": false,
|
|
"requires_context": []
|
|
},
|
|
{
|
|
"value": "São Paulo F.C.",
|
|
"strength": "strong",
|
|
"ambiguous": false,
|
|
"requires_context": []
|
|
},
|
|
{
|
|
"value": "SPFC",
|
|
"strength": "strong",
|
|
"ambiguous": false,
|
|
"requires_context": []
|
|
},
|
|
{
|
|
"value": "Tricolor Paulista",
|
|
"strength": "strong",
|
|
"ambiguous": false,
|
|
"requires_context": [
|
|
"football"
|
|
]
|
|
},
|
|
{
|
|
"value": "Clube da Fé",
|
|
"strength": "medium",
|
|
"ambiguous": true,
|
|
"requires_context": [
|
|
"football",
|
|
"São Paulo FC",
|
|
"SPFC",
|
|
"Tricolor Paulista"
|
|
]
|
|
},
|
|
{
|
|
"value": "Soberano",
|
|
"strength": "medium",
|
|
"ambiguous": true,
|
|
"requires_context": [
|
|
"football",
|
|
"São Paulo FC",
|
|
"SPFC",
|
|
"Tricolor Paulista"
|
|
]
|
|
},
|
|
{
|
|
"value": "São Paulo",
|
|
"strength": "weak",
|
|
"ambiguous": true,
|
|
"requires_context": [
|
|
"football",
|
|
"club",
|
|
"team",
|
|
"match",
|
|
"goal",
|
|
"coach",
|
|
"stadium",
|
|
"championship",
|
|
"SPFC",
|
|
"Tricolor Paulista",
|
|
"Morumbi"
|
|
]
|
|
}
|
|
],
|
|
"anchors": [
|
|
"futebol",
|
|
"clube",
|
|
"time",
|
|
"equipe",
|
|
"tricolor",
|
|
"torcida",
|
|
"campeonato",
|
|
"partida",
|
|
"jogo",
|
|
"gol",
|
|
"técnico",
|
|
"elenco",
|
|
"jogador",
|
|
"estádio",
|
|
"Morumbi",
|
|
"MorumBIS",
|
|
"Estádio do Morumbi",
|
|
"Cícero Pompeu de Toledo",
|
|
"Libertadores",
|
|
"Copa Libertadores",
|
|
"Campeonato Brasileiro",
|
|
"Brasileirão",
|
|
"Copa do Brasil",
|
|
"Campeonato Paulista",
|
|
"Paulistão",
|
|
"Mundial de Clubes",
|
|
"Rogério Ceni",
|
|
"Raí",
|
|
"Telê Santana",
|
|
"Luis Fabiano",
|
|
"Luís Fabiano",
|
|
"Muricy Ramalho",
|
|
"Calleri",
|
|
"Luciano",
|
|
"Lucas Moura"
|
|
],
|
|
"anchor_groups": {
|
|
"strong": [
|
|
"SPFC",
|
|
"São Paulo FC",
|
|
"São Paulo Futebol Clube",
|
|
"Tricolor Paulista",
|
|
"Morumbi",
|
|
"MorumBIS",
|
|
"Estádio do Morumbi",
|
|
"Cícero Pompeu de Toledo",
|
|
"Rogério Ceni",
|
|
"Raí",
|
|
"Telê Santana"
|
|
],
|
|
"medium": [
|
|
"Libertadores",
|
|
"Copa Libertadores",
|
|
"Campeonato Brasileiro",
|
|
"Brasileirão",
|
|
"Copa do Brasil",
|
|
"Campeonato Paulista",
|
|
"Paulistão",
|
|
"Mundial de Clubes",
|
|
"Luis Fabiano",
|
|
"Luís Fabiano",
|
|
"Muricy Ramalho"
|
|
],
|
|
"weak": [
|
|
"futebol",
|
|
"clube",
|
|
"time",
|
|
"equipe",
|
|
"tricolor",
|
|
"torcida",
|
|
"campeonato",
|
|
"partida",
|
|
"jogo",
|
|
"gol",
|
|
"técnico",
|
|
"elenco",
|
|
"jogador",
|
|
"estádio"
|
|
],
|
|
"volatile": [
|
|
"Calleri",
|
|
"Luciano",
|
|
"Lucas Moura"
|
|
]
|
|
},
|
|
"negative_anchors": [
|
|
"cidade de São Paulo",
|
|
"município de São Paulo",
|
|
"estado de São Paulo",
|
|
"governo de São Paulo",
|
|
"governo do estado de São Paulo",
|
|
"prefeitura de São Paulo",
|
|
"prefeito de São Paulo",
|
|
"capital paulista",
|
|
"região metropolitana de São Paulo",
|
|
"trânsito em São Paulo",
|
|
"chuva em São Paulo",
|
|
"violência em São Paulo",
|
|
"segurança pública em São Paulo",
|
|
"evento em São Paulo",
|
|
"show em São Paulo",
|
|
"restaurante em São Paulo",
|
|
"bairro de São Paulo",
|
|
"bolsa de valores de São Paulo",
|
|
"B3",
|
|
"São Paulo Fashion Week",
|
|
"Universidade de São Paulo",
|
|
"USP"
|
|
],
|
|
"negative_anchor_groups": {
|
|
"geo_political": [
|
|
"cidade de São Paulo",
|
|
"município de São Paulo",
|
|
"estado de São Paulo",
|
|
"governo de São Paulo",
|
|
"governo do estado de São Paulo",
|
|
"prefeitura de São Paulo",
|
|
"prefeito de São Paulo",
|
|
"capital paulista",
|
|
"região metropolitana de São Paulo"
|
|
],
|
|
"urban_news": [
|
|
"trânsito em São Paulo",
|
|
"chuva em São Paulo",
|
|
"violência em São Paulo",
|
|
"segurança pública em São Paulo",
|
|
"bairro de São Paulo"
|
|
],
|
|
"non_sports_events": [
|
|
"evento em São Paulo",
|
|
"show em São Paulo",
|
|
"restaurante em São Paulo",
|
|
"São Paulo Fashion Week"
|
|
],
|
|
"institutions_or_finance": [
|
|
"bolsa de valores de São Paulo",
|
|
"B3",
|
|
"Universidade de São Paulo",
|
|
"USP"
|
|
]
|
|
},
|
|
"graph_version": "spfc-graph-snapshot-v1",
|
|
"related_entities": [
|
|
{
|
|
"entity_id": "ecp_morumbi",
|
|
"name": "MorumBIS",
|
|
"canonical_name": "Estádio Cícero Pompeu de Toledo",
|
|
"aliases": [
|
|
"Morumbi",
|
|
"MorumBIS",
|
|
"Estádio do Morumbi",
|
|
"Cícero Pompeu de Toledo",
|
|
"Estádio Cícero Pompeu de Toledo"
|
|
],
|
|
"entity_type": "sports_venue",
|
|
"relation_type": "HOME_STADIUM",
|
|
"weight": 0.95,
|
|
"confidence": 0.95,
|
|
"scope_terms": [
|
|
"football",
|
|
"stadium",
|
|
"match",
|
|
"club",
|
|
"torcida",
|
|
"jogo",
|
|
"campeonato",
|
|
"São Paulo FC",
|
|
"SPFC"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_rogerio_ceni",
|
|
"name": "Rogério Ceni",
|
|
"canonical_name": "Rogério Ceni",
|
|
"aliases": [
|
|
"Rogério Ceni",
|
|
"Ceni",
|
|
"M1TO",
|
|
"Mito"
|
|
],
|
|
"entity_type": "athlete_or_coach",
|
|
"relation_type": "HAS_IDOL",
|
|
"weight": 0.9,
|
|
"confidence": 0.95,
|
|
"scope_terms": [
|
|
"football",
|
|
"goalkeeper",
|
|
"idol",
|
|
"coach",
|
|
"history",
|
|
"SPFC",
|
|
"tricolor"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_rai",
|
|
"name": "Raí",
|
|
"canonical_name": "Raí Souza Vieira de Oliveira",
|
|
"aliases": [
|
|
"Raí",
|
|
"Rai Souza Vieira de Oliveira",
|
|
"Raí Souza"
|
|
],
|
|
"entity_type": "athlete",
|
|
"relation_type": "HAS_IDOL",
|
|
"weight": 0.85,
|
|
"confidence": 0.9,
|
|
"scope_terms": [
|
|
"football",
|
|
"idol",
|
|
"midfielder",
|
|
"history",
|
|
"SPFC",
|
|
"tricolor"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_tele_santana",
|
|
"name": "Telê Santana",
|
|
"canonical_name": "Telê Santana",
|
|
"aliases": [
|
|
"Telê Santana",
|
|
"Tele Santana"
|
|
],
|
|
"entity_type": "coach",
|
|
"relation_type": "HISTORIC_COACH",
|
|
"weight": 0.85,
|
|
"confidence": 0.9,
|
|
"scope_terms": [
|
|
"football",
|
|
"coach",
|
|
"history",
|
|
"Libertadores",
|
|
"Mundial",
|
|
"SPFC",
|
|
"tricolor"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_muricy_ramalho",
|
|
"name": "Muricy Ramalho",
|
|
"canonical_name": "Muricy Ramalho",
|
|
"aliases": [
|
|
"Muricy Ramalho",
|
|
"Muricy"
|
|
],
|
|
"entity_type": "coach",
|
|
"relation_type": "HISTORIC_COACH",
|
|
"weight": 0.78,
|
|
"confidence": 0.85,
|
|
"scope_terms": [
|
|
"football",
|
|
"coach",
|
|
"Brasileirão",
|
|
"SPFC",
|
|
"tricolor"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_luis_fabiano",
|
|
"name": "Luis Fabiano",
|
|
"canonical_name": "Luís Fabiano",
|
|
"aliases": [
|
|
"Luis Fabiano",
|
|
"Luís Fabiano",
|
|
"Fabuloso"
|
|
],
|
|
"entity_type": "athlete",
|
|
"relation_type": "FORMER_PLAYER",
|
|
"weight": 0.75,
|
|
"confidence": 0.85,
|
|
"scope_terms": [
|
|
"football",
|
|
"striker",
|
|
"player",
|
|
"goal",
|
|
"SPFC",
|
|
"tricolor"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_corinthians",
|
|
"name": "Sport Club Corinthians Paulista",
|
|
"canonical_name": "Sport Club Corinthians Paulista",
|
|
"aliases": [
|
|
"Corinthians",
|
|
"Sport Club Corinthians Paulista",
|
|
"Timão"
|
|
],
|
|
"entity_type": "sports_club",
|
|
"relation_type": "RIVAL_OF",
|
|
"weight": 0.75,
|
|
"confidence": 0.9,
|
|
"scope_terms": [
|
|
"football",
|
|
"derby",
|
|
"rival",
|
|
"clássico",
|
|
"Majestoso",
|
|
"Campeonato Paulista",
|
|
"Brasileirão"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_palmeiras",
|
|
"name": "Sociedade Esportiva Palmeiras",
|
|
"canonical_name": "Sociedade Esportiva Palmeiras",
|
|
"aliases": [
|
|
"Palmeiras",
|
|
"Sociedade Esportiva Palmeiras",
|
|
"Verdão"
|
|
],
|
|
"entity_type": "sports_club",
|
|
"relation_type": "RIVAL_OF",
|
|
"weight": 0.72,
|
|
"confidence": 0.9,
|
|
"scope_terms": [
|
|
"football",
|
|
"derby",
|
|
"rival",
|
|
"clássico",
|
|
"Choque-Rei",
|
|
"Campeonato Paulista",
|
|
"Brasileirão"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_santos_fc",
|
|
"name": "Santos Futebol Clube",
|
|
"canonical_name": "Santos Futebol Clube",
|
|
"aliases": [
|
|
"Santos",
|
|
"Santos FC",
|
|
"Santos Futebol Clube",
|
|
"Peixe"
|
|
],
|
|
"entity_type": "sports_club",
|
|
"relation_type": "RIVAL_OF",
|
|
"weight": 0.68,
|
|
"confidence": 0.85,
|
|
"scope_terms": [
|
|
"football",
|
|
"derby",
|
|
"rival",
|
|
"clássico",
|
|
"San-São",
|
|
"Campeonato Paulista",
|
|
"Brasileirão"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_libertadores",
|
|
"name": "Copa Libertadores da América",
|
|
"canonical_name": "Copa Libertadores da América",
|
|
"aliases": [
|
|
"Libertadores",
|
|
"Copa Libertadores",
|
|
"Copa Libertadores da América",
|
|
"CONMEBOL Libertadores"
|
|
],
|
|
"entity_type": "sports_competition",
|
|
"relation_type": "PLAYS_COMPETITION",
|
|
"weight": 0.65,
|
|
"confidence": 0.85,
|
|
"scope_terms": [
|
|
"football",
|
|
"competition",
|
|
"continental",
|
|
"CONMEBOL",
|
|
"title",
|
|
"SPFC"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_campeonato_brasileiro",
|
|
"name": "Campeonato Brasileiro Série A",
|
|
"canonical_name": "Campeonato Brasileiro Série A",
|
|
"aliases": [
|
|
"Campeonato Brasileiro",
|
|
"Brasileirão",
|
|
"Brasileiro Série A",
|
|
"Série A"
|
|
],
|
|
"entity_type": "sports_competition",
|
|
"relation_type": "PLAYS_COMPETITION",
|
|
"weight": 0.62,
|
|
"confidence": 0.85,
|
|
"scope_terms": [
|
|
"football",
|
|
"competition",
|
|
"Brazil",
|
|
"league",
|
|
"club",
|
|
"table",
|
|
"match"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_copa_do_brasil",
|
|
"name": "Copa do Brasil",
|
|
"canonical_name": "Copa do Brasil",
|
|
"aliases": [
|
|
"Copa do Brasil"
|
|
],
|
|
"entity_type": "sports_competition",
|
|
"relation_type": "PLAYS_COMPETITION",
|
|
"weight": 0.58,
|
|
"confidence": 0.8,
|
|
"scope_terms": [
|
|
"football",
|
|
"competition",
|
|
"Brazil",
|
|
"knockout",
|
|
"club",
|
|
"match"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
},
|
|
{
|
|
"entity_id": "ecp_campeonato_paulista",
|
|
"name": "Campeonato Paulista",
|
|
"canonical_name": "Campeonato Paulista",
|
|
"aliases": [
|
|
"Campeonato Paulista",
|
|
"Paulistão",
|
|
"Paulista"
|
|
],
|
|
"entity_type": "sports_competition",
|
|
"relation_type": "PLAYS_COMPETITION",
|
|
"weight": 0.58,
|
|
"confidence": 0.8,
|
|
"scope_terms": [
|
|
"football",
|
|
"competition",
|
|
"São Paulo state",
|
|
"club",
|
|
"derby"
|
|
],
|
|
"classification_effect": "contextual_inherent_candidate"
|
|
}
|
|
],
|
|
"classification_profile": {
|
|
"labels": [
|
|
"DIRECT_INHERENT",
|
|
"CONTEXTUAL_INHERENT",
|
|
"TANGENTIAL",
|
|
"NOT_RELATED",
|
|
"UNCERTAIN"
|
|
],
|
|
"direct_inherent": {
|
|
"description": "Content is directly about São Paulo Futebol Clube.",
|
|
"strong_positive_signals": [
|
|
"canonical_name",
|
|
"strong_alias",
|
|
"SPFC",
|
|
"Tricolor Paulista",
|
|
"official_domain",
|
|
"club-specific anchor"
|
|
],
|
|
"minimum_expected_context": [
|
|
"football",
|
|
"club",
|
|
"match",
|
|
"player",
|
|
"coach",
|
|
"stadium",
|
|
"competition"
|
|
]
|
|
},
|
|
"contextual_inherent": {
|
|
"description": "Content is mainly about a strongly related entity, but relevant to São Paulo Futebol Clube.",
|
|
"required_signals": [
|
|
"related_entity_match",
|
|
"relation_weight >= 0.65",
|
|
"sports_or_football_context"
|
|
],
|
|
"examples": [
|
|
"article about Rogério Ceni as São Paulo idol or coach",
|
|
"article about Raí in relation to São Paulo history",
|
|
"article about MorumBIS as São Paulo home venue",
|
|
"article about São Paulo rivalry with Corinthians or Palmeiras"
|
|
]
|
|
},
|
|
"tangential": {
|
|
"description": "Content mentions São Paulo FC or a related term, but the entity is not meaningfully part of the subject.",
|
|
"examples": [
|
|
"generic Brasileirão table with São Paulo only listed among many clubs",
|
|
"article about another club that only mentions upcoming match against São Paulo"
|
|
]
|
|
},
|
|
"not_related": {
|
|
"description": "Content is about another São Paulo meaning or unrelated subject.",
|
|
"strong_negative_signals": [
|
|
"city_or_state_context",
|
|
"government_context",
|
|
"weather_or_traffic_context",
|
|
"university_context",
|
|
"finance_context",
|
|
"fashion_or_event_context"
|
|
]
|
|
},
|
|
"uncertain": {
|
|
"description": "Evidence is weak, conflicting, or insufficient.",
|
|
"fallback_recommendation": "send_to_llm_judge"
|
|
}
|
|
},
|
|
"scoring_hints": {
|
|
"strong_alias_weight": 0.45,
|
|
"ambiguous_alias_weight": 0.12,
|
|
"strong_anchor_weight": 0.25,
|
|
"medium_anchor_weight": 0.15,
|
|
"weak_anchor_weight": 0.05,
|
|
"negative_anchor_penalty": 0.4,
|
|
"related_entity_weight_multiplier": 0.5,
|
|
"official_domain_weight": 0.5,
|
|
"direct_threshold": 0.75,
|
|
"contextual_threshold": 0.65,
|
|
"tangential_threshold": 0.35,
|
|
"uncertain_band": [
|
|
0.45,
|
|
0.65
|
|
]
|
|
},
|
|
"output_contract": {
|
|
"label": "DIRECT_INHERENT | CONTEXTUAL_INHERENT | TANGENTIAL | NOT_RELATED | UNCERTAIN",
|
|
"confidence": "number from 0.0 to 1.0",
|
|
"matched_signals": "array of matched positive signals",
|
|
"negative_signals": "array of matched negative signals",
|
|
"related_entity_matches": "array of matched related entities",
|
|
"explanation": "short human-readable explanation",
|
|
"needs_llm_fallback": "boolean"
|
|
},
|
|
"quality": {
|
|
"profile_confidence": 0.86,
|
|
"intended_use": "local deterministic NLP POC fixture",
|
|
"not_intended_for": [
|
|
"final production ECP schema",
|
|
"canonical graph storage",
|
|
"legal/compliance decisioning",
|
|
"fully automated publishing without review"
|
|
],
|
|
"known_limitations": [
|
|
"Current player anchors may become stale.",
|
|
"The alias 'São Paulo' is highly ambiguous and must never be enough alone for DIRECT_INHERENT.",
|
|
"Generic football terms are weak signals only.",
|
|
"Related entities should usually produce CONTEXTUAL_INHERENT, not DIRECT_INHERENT.",
|
|
"This profile is optimized for Portuguese content first."
|
|
]
|
|
},
|
|
"sources": [
|
|
{
|
|
"type": "wikidata",
|
|
"url": "https://www.wikidata.org/wiki/Q38568",
|
|
"supports": [
|
|
"qid",
|
|
"canonical identity",
|
|
"entity type",
|
|
"inception"
|
|
]
|
|
},
|
|
{
|
|
"type": "official_site",
|
|
"url": "https://www.saopaulofc.net/",
|
|
"supports": [
|
|
"official domain",
|
|
"club identity",
|
|
"sports sections"
|
|
]
|
|
},
|
|
{
|
|
"type": "official_site",
|
|
"url": "https://www.saopaulofc.net/institucional/sobre-o-sao-paulo-fc/",
|
|
"supports": [
|
|
"history",
|
|
"founded year",
|
|
"club narrative",
|
|
"MorumBIS",
|
|
"historic figures"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"created_for": "ecp-nlp-classifier-poc",
|
|
"created_at": "2026-08-20",
|
|
"graph_snapshot": "spfc-graph-snapshot-v1",
|
|
"review_status": "example_ready"
|
|
}
|
|
} |