Usuario:JoaquinFerrero/MedalleroSochi2014

De Wikipedia, la enciclopedia libre

Programa para la actualización automática del Medallero de los Juegos Olímpicos Sochi 2014[editar]

#!/usr/bin/env perl
# *- encode: utf8. tabs: 8 spaces. -*
#
# medalleroSochi2014.pl
#
# Autor:
#       Joaquín Ferrero
#
# Descripción:
#       Actualización automática de medalleros olímpicos en Wikipedia.
#
# Entrada: ninguna
# Salida:  ninguna
#
# Historial:
#   2014.02.08 : Versión Sochi Invierno 2014
#   2013.08.10 : Versión Moscú Atletismo 2013
#   2013.06.26 : Versión Mersin Mediterráneo 2013
#   2012.08.31 : Versión Londres Paralímpicos 2012
#   2012.07.31 : Versión Londres Verano 2012
#   2010.03.20 : Versión Medellin Sudamericanos 2010
#   2010.03.13 : Versión Vancouver Paralimpicos 2010
#   2010.02.16 : Versión Vancouver Invierno 2010
#   2008.09.07 : Versión Pekín Verano 2008
#

### Bibliotecas -------------------------------------------------------------
use Modern::Perl 2013;		# Programamos en Perl moderno
use utf8::all;			# Activar todo el soporte para UTF-8. Realmente todo
use Mojo::UserAgent;		# Un poco de mojo...
use MediaWiki::API;		# Y mucha Wikipedia
#use Data::Dumper;

### Configuración -----------------------------------------------------------
my $PAÍS_ANFITRIÓN		= 'RUS';
my $URL_MEDALLERO		= 'http://www.sochi2014.com/en/medal-standings';
my $WIKIPEDIA_PÁGINA_MEDALLERO	= 'Anexo:Medallero de los Juegos Olímpicos de Sochi 2014';
my $WIKIPEDIA_PÁGINA_TEST	= 'Wikipedia:Zona de pruebas/5';
my $WIKIPEDIA_USUARIO_LOGIN	= 'user';
my $WIKIPEDIA_USUARIO_PASSW	= 'pass';
my $WIKIPEDIA_API_URL		= 'http://es.wikipedia.org/w/api.php';
my $DEBUG			=  1;					# 0, 1 o 2
my $título_página_wiki		= $WIKIPEDIA_PÁGINA_MEDALLERO;		# $WIKIPEDIA_PÁGINA_TEST
my $medallero_wiki_cabeza	= <<"EOF";
== Medallero ==
<!--
                                   ATENCIÓN

     Esta tabla se actualiza de forma automática cada 5 min. durante el periodo de los juegos.

            CUALQUIER cambio realizado de forma manual se perderá.

               AVISAR de incidencias al usuario JoaquinFerrero.
--></noinclude>
EOF
my $medallero_wiki_aviso_corte	= <<'EOP10';
<includeonly><!-- Para cerrar la tabla en el artículo principal -->|}</includeonly><noinclude><!--
Para que automáticamente se genere una lista de sólo 10 países en el artículo principal, mover el tag "noinclude"
tras los 10 mejores países clasificados -->
EOP10
### Fin de configuración ----------------------------------------------------

## Obtención de los resultados ----------------------------------------------
my $medallero_html;

#use Mojo::DOM;
#$medallero_html = do { local $/; open HTML, '/home/explorer/Documentos/Desarrollo/medallero/medalleroSochi2014.html'; <HTML> };
#my $dom = Mojo::DOM->new($medallero_html);
#$medallero_html = $dom->find("table.RSPEAK_CONTENT")->[0];

my $ua = Mojo::UserAgent->new(
    name		=> 'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:14.0) Mojolicious/2012 Wikipedia/es',
    request_timeout	=> 20,
);

for my $retry (1 .. 3) {				# Tres intentos
    $medallero_html = $ua->get(
        $URL_MEDALLERO,
        {
        }
    )->res->dom->find("table.RSPEAK_CONTENT")->[0];	# CSS Selector

    last if defined $medallero_html;

    say "Intento fallido $retry..."			if $DEBUG;
    sleep 30;
}

die "ERROR: No he podido leer la página del medallero oficial\n"
    if not defined $medallero_html;

## Datos de los países ------------------------------------------------------
my %paises;

while (my $l = <DATA>) {
    chomp $l;
    my ($id, $valor) = split " ", $l, 2;
    $paises{$id} = $valor;
}

## Extracción de resultados -------------------------------------------------
my @tabla_medallero_oficial;						# aquí guardamos el resultado de la extracción

my $posición          = 1;						# Renumeración de las posiciones
my $posición_absoluta = 1;						# Posición real dentro del global de posiciones

my @filas = $medallero_html->find("tr")->each;
shift @filas;								# la primera línea de la tabla no es interesante

for my $fila (@filas) {
    my $resultados;							# resultados para un participante

    my @celdas = $fila->find("td")->each;
    #next if @celdas != 6;

    next if $celdas[1]->attr('class') !~ / (...)$/;

    $resultados->{'COI'} = uc $1;					# extraemos el código COI del país

    my @medallas = map {
	my $texto = $_->text;
	$texto  = 0 if $texto eq '-';
	$texto += 0;
	$texto }
	@celdas[2..5];							# valores de las medallas (oro, plata, bronce, totales)
    $resultados->{'medallas'} = \@medallas;

    # ajustar posición según logros alcanzados
    if (	@tabla_medallero_oficial > 0				# solo a partir de la segunda fila
	and (
                $tabla_medallero_oficial[-1]{'medallas'}[0] > $medallas[0]	# Oro
            or	$tabla_medallero_oficial[-1]{'medallas'}[1] > $medallas[1]	# Plata
            or	$tabla_medallero_oficial[-1]{'medallas'}[2] > $medallas[2]	# Bronce
        )
    ) {
        $posición = $posición_absoluta;					# sí: su posición es una más que el anterior
    }

    $resultados->{'posición'} = $posición;				# guardamos nueva posición
    push @tabla_medallero_oficial, $resultados;				# nueva fila en el medallero

    $posición_absoluta++;
}

die "ERROR: No he leído la tabla del medallero oficial"
    if ! @tabla_medallero_oficial;

## Confección del Medallero en formato wiki ---------------------------------
my $medallero_wiki;							# Medallero en formato Wiki
my @totales_medallero;          					# Almacena la suma de las medallas

# Cabecera de la tabla
$medallero_wiki  = $medallero_wiki_cabeza;
$medallero_wiki .= "{{Leyenda|#CCCCFF|País organizador|border=solid 1px #AAA}}\n";
$medallero_wiki .= "{| {{Medallero|tipo=1|ancho=60%}}\n";

# Filas de la tabla
my $DCOL = ' || ';
my $n_fila = 1;
my $aviso_corte_puesto = 0;

for my $fila (@tabla_medallero_oficial) {
    my @medallas = @{$fila->{'medallas'}};						# Número de medallas

    last if $medallas[-1] == 0;								# Paramos si no tiene medallas

    map { $totales_medallero[$_] += $medallas[$_] } 0 .. 3;				# Cálculo de los totales

    $medallero_wiki .= '|-';									# Nueva fila
    $medallero_wiki .= '-bgcolor=ccccff' if $fila->{'COI'} eq $PAÍS_ANFITRIÓN;			# destaque
    $medallero_wiki .= "\n";
    $medallero_wiki .= '| '
		    . join $DCOL =>
		    "'''$fila->{'posición'}'''",						# posición
                    "$paises{$fila->{'COI'}}",							# país
		    @medallas									# medallas
		    ;
    $medallero_wiki .= "\n";

    if ($n_fila == 10) {
	$medallero_wiki .= $medallero_wiki_aviso_corte;
    	$aviso_corte_puesto = 1;
    }

    $n_fila++;
}

if (not $aviso_corte_puesto) {
    $medallero_wiki .= $medallero_wiki_aviso_corte;
}

# Totales y fin de la tabla
$medallero_wiki .= "|-\n" . join($DCOL, '! colspan="2" | Total', @totales_medallero) . "\n|}";
$medallero_wiki .= "\n\n";

## Conexión con Wikipedia ---------------------------------------------------
my $Wikipedia = MediaWiki::API->new({
    api_url     => $WIKIPEDIA_API_URL,
    retries     => 3,
    retry_delay => 30,
});

$Wikipedia->login({
    lgname      => $WIKIPEDIA_USUARIO_LOGIN,
    lgpassword  => $WIKIPEDIA_USUARIO_PASSW,
})
or die $Wikipedia->{error}->{code} . ': ' . $Wikipedia->{error}->{details};

## Actualización de la página del medallero ---------------------------------
my $página_wiki;						# Contenido de la página wiki actual
my $página_antes_wiki;						# Contenido de la página wiki anterior

my $página_wiki_ref = $Wikipedia->get_page({
    title => $título_página_wiki,
});

die "ERROR: No conseguí la página del medallero\n"
    if $página_wiki_ref->{missing};

$página_wiki = $página_antes_wiki = $página_wiki_ref->{'*'};	# Cómo es la página en este momento 

# Editamos la página
if ($página_wiki =~ s/^=+ Medallero =+.+?(?=^=)/$medallero_wiki/sm) {

    if ($página_wiki  ne  $página_antes_wiki) {			# Si hay realmente un cambio, la editamos
        $Wikipedia->edit({
                 action        => 'edit',
                 text          => $página_wiki,
                 title         => $título_página_wiki,
                 basetimestamp => $página_wiki_ref->{timestamp},
                 summary       => 'Actualización automática del medallero',
            })
            or die $Wikipedia->{error}->{code} . ': ' . $Wikipedia->{error}->{details}
            ;

        say 'Medallero actualizado'		if $DEBUG;
    }
    else {
	say 'No hay cambios'			if $DEBUG == 2;
    }
}
else {
    die 'ERROR: no encuentro la sección del medallero en la página';
}

__DATA__
ALB {{BanderaOL|Albania|ALB|ed=Sochi 2014}}
GER {{BanderaOL|Alemania|GER|ed=Sochi 2014}}
AND {{BanderaOL|Andorra|AND|ed=Sochi 2014}}
ARG {{BanderaOL|Argentina|ARG|ed=Sochi 2014}}
ARM {{BanderaOL|Armenia|ARM|ed=Sochi 2014}}
AUS {{BanderaOL|Australia|AUS|ed=Sochi 2014}}
AUT {{BanderaOL|Austria|AUT|ed=Sochi 2014}}
AZE {{BanderaOL|Azerbaiyán|AZE|ed=Sochi 2014}}
BEL {{BanderaOL|Bélgica|BEL|ed=Sochi 2014}}
BER {{BanderaOL|Bermudas|BER|ed=Sochi 2014}}
BLR {{BanderaOL|Bielorrusia|BLR|ed=Sochi 2014}}
BIH {{BanderaOL|Bosnia y Herzegovina|BIH|ed=Sochi 2014}}
BRA {{BanderaOL|Brasil|BRA|ed=Sochi 2014}}
BUL {{BanderaOL|Bulgaria|BUL|ed=Sochi 2014}}
CAN {{BanderaOL|Canadá|CAN|ed=Sochi 2014}}
CHI {{BanderaOL|Chile|CHI|ed=Sochi 2014}}
CHN {{BanderaOL|China|CHN|ed=Sochi 2014}}
TPE {{BanderaOL|China Taipéi|TPE|ed=Sochi 2014}}
CYP {{BanderaOL|Chipre|CYP|ed=Sochi 2014}}
KOR {{BanderaOL|Corea del Sur|KOR|ed=Sochi 2014}}
CRO {{BanderaOL|Croacia|CRO|ed=Sochi 2014}}
DEN {{BanderaOL|Dinamarca|DEN|ed=Sochi 2014}}
DMA {{BanderaOL|Dominica|DMA|ed=Sochi 2014}}
SVK {{BanderaOL|Eslovaquia|SVK|ed=Sochi 2014}}
SLO {{BanderaOL|Eslovenia|SLO|ed=Sochi 2014}}
ESP {{BanderaOL|España|ESP|ed=Sochi 2014}}
USA {{BanderaOL|Estados Unidos|USA|ed=Sochi 2014}}
EST {{BanderaOL|Estonia|EST|ed=Sochi 2014}}
PHI {{BanderaOL|Filipinas|PHI|ed=Sochi 2014}}
FIN {{BanderaOL|Finlandia|FIN|ed=Sochi 2014}}
FRA {{BanderaOL|Francia|FRA|ed=Sochi 2014}}
GEO {{BanderaOL|Georgia|GEO|ed=Sochi 2014}}
GRE {{BanderaOL|Grecia|GRE|ed=Sochi 2014}}
HKG {{BanderaOL|Hong Kong|HKG|ed=Sochi 2014}}
HUN {{BanderaOL|Hungría|HUN|ed=Sochi 2014}}
IRI {{BanderaOL|Irán|IRI|ed=Sochi 2014}}
IRL {{BanderaOL|Irlanda|IRL|ed=Sochi 2014}}
ISL {{BanderaOL|Islandia|ISL|ed=Sochi 2014}}
CAY {{BanderaOL|Islas Caimán|CAY|ed=Sochi 2014}}
IVB {{BanderaOL|Islas Vírgenes Británicas|IVB|ed=Sochi 2014}}
ISV {{BanderaOL|Islas Vírgenes de los Estados Unidos|ISV|ed=Sochi 2014}}
ISR {{BanderaOL|Israel|ISR|ed=Sochi 2014}}
ITA {{BanderaOL|Italia|ITA|ed=Sochi 2014}}
JAM {{BanderaOL|Jamaica|JAM|ed=Sochi 2014}}
JPN {{BanderaOL|Japón|JPN|ed=Sochi 2014}}
KAZ {{BanderaOL|Kazajistán|KAZ|ed=Sochi 2014}}
KGZ {{BanderaOL|Kirguistán|KGZ|ed=Sochi 2014}}
LAT {{BanderaOL|Letonia|LAT|ed=Sochi 2014}}
LIB {{BanderaOL|Líbano|LIB|ed=Sochi 2014}}
LIE {{BanderaOL|Liechtenstein|LIE|ed=Sochi 2014}}
LTU {{BanderaOL|Lituania|LTU|ed=Sochi 2014}}
LUX {{BanderaOL|Luxemburgo|LUX|ed=Sochi 2014}}
MKD {{BanderaOL|Macedonia|MKD|ed=Sochi 2014}}
MLT {{BanderaOL|Malta|MLT|ed=Sochi 2014}}
MAR {{BanderaOL|Marruecos|MAR|ed=Sochi 2014}}
MEX {{BanderaOL|México|MEX|ed=Sochi 2014}}
MDA {{BanderaOL|Moldavia|MDA|ed=Sochi 2014}}
MON {{BanderaOL|Mónaco|MON|ed=Sochi 2014}}
MGL {{BanderaOL|Mongolia|MGL|ed=Sochi 2014}}
MNE {{BanderaOL|Montenegro|MNE|ed=Sochi 2014}}
NEP {{BanderaOL|Nepal|NEP|ed=Sochi 2014}} 
NOR {{BanderaOL|Noruega|NOR|ed=Sochi 2014}}
NZL {{BanderaOL|Nueva Zelanda|NZL|ed=Sochi 2014}}
NED {{BanderaOL|Países Bajos|NED|ed=Sochi 2014}}
PAK {{BanderaOL|Pakistán|PAK|ed=Sochi 2014}}
PAR {{BanderaOL|Paraguay|PAR|ed=Sochi 2014}}
IOP {{Bandera|Juegos Olímpicos}} [[Participantes Olímpicos Independientes]] (IOP)
PER {{BanderaOL|Perú|PER|ed=Sochi 2014}}
POL {{BanderaOL|Polonia|POL|ed=Sochi 2014}}
POR {{BanderaOL|Portugal|POR|ed=Sochi 2014}}
GBR {{BanderaOL|Reino Unido|GBR|ed=Sochi 2014}}
CZE {{BanderaOL|República Checa|CZE|ed=Sochi 2014}}
ROU {{BanderaOL|Rumania|ROU|ed=Sochi 2014}}
RUS {{BanderaOL|Rusia|RUS|ed=Sochi 2014}}
SMR {{BanderaOL|San Marino|SMR|ed=Sochi 2014}}
SRB {{BanderaOL|Serbia|SRB|ed=Sochi 2014}}
SWE {{BanderaOL|Suecia|SWE|ed=Sochi 2014}}
SUI {{BanderaOL|Suiza|SUI|ed=Sochi 2014}}
THA {{BanderaOL|Tailandia|THA|ed=Sochi 2014}}
TJK {{BanderaOL|Tayikistán|TJK|ed=Sochi 2014}}
TLS {{BanderaOL|Timor Oriental|TLS|ed=Sochi 2014}}
TGA {{BanderaOL|Togo|TGA|ed=Sochi 2014}}
TOG {{BanderaOL|Tonga|TOG|ed=Sochi 2014}}
TUR {{BanderaOL|Turquía|TUR|ed=Sochi 2014}}
UKR {{BanderaOL|Ucrania|UKR|ed=Sochi 2014}}
UZB {{BanderaOL|Uzbekistán|UZB|ed=Sochi 2014}}
VEN {{BanderaOL|Venezuela|VEN|ed=Sochi 2014}}
ZIM {{BanderaOL|Zimbabue|ZIM|ed=Sochi 2014}}