Final_Assignment_Template / wikipedia_util.py
gdms's picture
correção
1eba8dd
from datetime import datetime, timezone
from typing import Tuple, List
import urllib
from pydantic import BaseModel
import requests
import wikipediaapi
class Wikipedia_Historical_Page(BaseModel):
title: str
url: str
revision_id: str
timestamp: str
class Wikipedia_Util:
WIKI_LANG = 'en' # Linguagem da Wikipedia (atualizado para inglês)
MEDIAWIKI_API_URL = f"https://{WIKI_LANG}.wikipedia.org/w/api.php"
HEADERS = {
'User-Agent': 'MyCoolSearchBot/1.0 ([email protected])'
}
wiki_executor = wikipediaapi.Wikipedia(
language=WIKI_LANG,
extract_format=wikipediaapi.ExtractFormat.HTML, # Usado apenas para page.exists()
user_agent='MyCoolSearchBot/1.0 ([email protected])' # Definir um User-Agent é boa prática
)
@staticmethod
def get_wikipedia_revision_info(page_title: str, target_date_str: str) -> Tuple[str,str]:
"""
Busca o ID e timestamp da revisão mais próxima (<=) da data fornecida via API MediaWiki.
Args:
page_title: wikipedia encontra páginas históricas pelo titulo
target_date_str: data no formato "YYYY-MM-DD"
Returns:
Uma tupla contendo o ID da revisão e o timestamp da revisão.
"""
try:
# Converte a data string para um objeto datetime e formata para ISO 8601 com Z (UTC)
target_dt = datetime.strptime(target_date_str, '%Y-%m-%d')
# Precisamos do final do dia para garantir que incluímos todas as revisões daquele dia
target_dt_end_of_day = target_dt.replace(hour=23, minute=59, second=59, tzinfo=timezone.utc)
target_timestamp_iso = target_dt_end_of_day.strftime('%Y-%m-%dT%H:%M:%SZ')
except ValueError:
print("Formato de data inválido. Use AAAA-MM-DD.")
return None, None
params = {
"action": "query",
"prop": "revisions",
"titles": page_title,
"rvlimit": 1,
"rvdir": "older", # Busca a revisão imediatamente anterior ou igual ao timestamp
"rvprop": "ids|timestamp", # Queremos o ID da revisão e o timestamp
"rvstart": target_timestamp_iso, # Começa a busca a partir desta data/hora
"format": "json",
"formatversion": 2 # Formato JSON mais moderno e fácil de parsear
}
try:
print(f"Consultando API MediaWiki para revisão de '{page_title}' em {target_date_str}...")
response = requests.get(Wikipedia_Util.MEDIAWIKI_API_URL, params=params, headers=Wikipedia_Util.HEADERS, timeout=15)
response.raise_for_status()
data = response.json()
# Verifica se a página foi encontrada
page_data = data.get("query", {}).get("pages", [])
if not page_data or page_data[0].get("missing", False):
print(f"Página '{page_title}' não encontrada na API MediaWiki.")
# Tenta verificar com a biblioteca wikipediaapi como fallback (pode pegar redirecionamentos)
page = Wikipedia_Util.wiki_executor.page(page_title)
if page.exists():
print(f"Página '{page_title}' existe (possivelmente redirecionada para '{page.title}'). Tentando novamente com o título canônico...")
return Wikipedia_Util.get_wikipedia_revision_info(page.title, target_date_str) # Chama recursivamente com o título correto
else:
print(f"Página '{page_title}' realmente não encontrada.")
return None, None
# Extrai as revisões
revisions = page_data[0].get("revisions", [])
if not revisions:
print(f"Nenhuma revisão encontrada para '{page_title}' antes ou em {target_date_str}.")
# Pode acontecer se a página foi criada depois da data alvo
return None, None
revision = revisions[0]
revid = revision.get("revid")
timestamp = revision.get("timestamp")
print(f"Encontrada revisão: ID={revid}, Timestamp={timestamp}")
return revid, timestamp
except requests.exceptions.RequestException as e:
print(f"Erro ao chamar a API MediaWiki: {e}")
return None, None
except Exception as e:
print(f"Erro ao processar resposta da API MediaWiki: {e}")
return None, None
@staticmethod
def get_wikipedia_page_historical_content(page_title: str, target_date_str: str) -> Wikipedia_Historical_Page:
"""Obtém o conteúdo Markdown de uma revisão histórica específica da Wikipedia."""
# Busca o ID da revisão correta usando a API MediaWiki
revid, timestamp = Wikipedia_Util.get_wikipedia_revision_info(page_title, target_date_str)
if not revid:
print(f"Não foi possível encontrar uma revisão adequada para '{page_title}' em {target_date_str}.")
return None
# Constrói a URL para a revisão específica
# Nota: Codifica o título da página para a URL
# Precisamos garantir que estamos usando o título correto (pode ter sido redirecionado)
page_check = Wikipedia_Util.wiki_executor.page(page_title) # Verifica novamente para obter o título canônico se houve redirecionamento
if not page_check.exists():
print(f"Erro inesperado: Página '{page_title}' não encontrada após busca de revisão.")
return None
canonical_title = page_check.title
encoded_title = urllib.parse.quote(canonical_title.replace(' ', '_'))
revision_url = f"https://{Wikipedia_Util.WIKI_LANG}.wikipedia.org/w/index.php?title={encoded_title}&oldid={revid}"
return Wikipedia_Historical_Page(
title=canonical_title,
url=revision_url,
revision_id=str(revid), #parametro obrigatoriamente string
timestamp=timestamp
)