Usuario:JoaquinFerrero/MedalleroPortland2016

De Wikipedia, la enciclopedia libre
#!/usr/bin/env perl
# *- encode: utf8. tabs: 8 spaces. -*
#
# medalleroPortland2016.pl
#
# Autor:
#       Joaquín Ferrero
#
# Descripción:
#       Actualización automática de medalleros en Wikipedia.
#
# Entrada: ninguna
# Salida:  ninguna
#
# Historial:
#   2016.03.18 : Versión Portland Atletismo en Pista Cubierta 2016
#   2015.08.21 : Versión Pekín Atletismo 2015
#   2015.06.13 : Versión Baku Europeos 2015
#   2014.03.07 : Versión Sochi Paralímpicos Invierno 2014
#   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 v5.14.2;
use utf8::all;			# Activar todo el soporte para UTF-8. Realmente todo
use MediaWiki::API;		# Y mucha Wikipedia
use Mojo::UserAgent;		# Un poco de mojo...

use Data::Dumper;

### Configuración -----------------------------------------------------------
my $DEBUG			=  0;					# 0, 1 o 2
my $PAÍS_ANFITRIÓN		= 'USA';
my $URL_MEDALLERO		= 'http://www.iaaf.org/competitions/iaaf-world-indoor-championships/iaaf-world-indoor-championships-5681/medaltable';
my $WIKIPEDIA_PÁGINA_MEDALLERO	= 'Plantilla:Med-CMATLPC16';
#my $WIKIPEDIA_PÁGINA_MEDALLERO	= 'Campeonato Mundial de Atletismo en Pista Cubierta de 2016';
my $WIKIPEDIA_PÁGINA_TEST	= 'Wikipedia:Zona de pruebas/5';
my $WIKIPEDIA_USUARIO_LOGIN	= 'USER';
my $WIKIPEDIA_USUARIO_PASSW	= 'PASSWORD';
my $WIKIPEDIA_API_URL		= 'http://es.wikipedia.org/w/api.php';
my $título_página_wiki		= $WIKIPEDIA_PÁGINA_MEDALLERO; #  $WIKIPEDIA_PÁGINA_TEST;#  
my $medallero_wiki_cabeza	= <<'EOF';
<!-- Plantilla creada para actualizar automáticamente el medallero del Mundial de Pista Corta de 2016 de acuerdo a la página oficial del campeonato. No modificar. -->
<!-- 
                    _  _____ _____ _   _  ____ ___  __  _   _ 
                   / \|_   _| ____| \ | |/ ___|_ _|/_/ | \ | |
                  / _ \ | | |  _| |  \| | |    | |/ _ \|  \| |
                 / ___ \| | | |___| |\  | |___ | | |_| | |\  |
                /_/   \_\_| |_____|_| \_|\____|___\___/|_| \_|

                Este medallero se actualiza de forma automática
             cada 5 minutos durante el periodo de la competición.

            Cualquier cambio realizado de forma manual se perderá.

               Avisar de incidencias al usuario JoaquinFerrero.
-->
EOF
### Fin de configuración ----------------------------------------------------

## Obtención de los resultados ----------------------------------------------
my $ua = Mojo::UserAgent->new(
    name		=> 'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:14.0) Mojolicious/2015 Wikipedia/es',
    request_timeout	=> 20,
);

my $medallero_html;

for my $retry (1 .. 3) {				# Tres intentos
    $medallero_html = $ua->get(
        $URL_MEDALLERO,
        {
        }
    )->res->dom->at('table.records-table');		# Mojo::DOM::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;

say $medallero_html if $DEBUG == 2;;

## 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

for my $fila ($medallero_html->find("tr")->each) {
    my $resultados;							# resultados para un participante

    my @celdas = map { $_->all_text } $fila->find("td")->each;		# extraemos las celdas

    next if @celdas != 6;

    my $celda_bandera = $fila->at('img.tableflag');			# celda con la bandera
    my($bandera) = $celda_bandera =~ m{Flags/(.+?)[.]gif};

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

    my @medallas = map { 0 + $_ } @celdas[2..5];			# valores de las medallas (oro, plata, bronce, totales)

    $resultados->{'medallas'} = \@medallas;				# guardar

    # 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;

say Dumper \@tabla_medallero_oficial if $DEBUG == 2;

## 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 = 0;
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
			    "{{$fila->{'COI'}}}",							# país
			    @medallas									# medallas
		    ;
    $medallero_wiki .= "\n";

    $n_fila++;
}

# Totales y fin de la tabla
$medallero_wiki .= "|- align=right\n";
$medallero_wiki .= "| '''Total''' || align=left | '''$n_fila países''' ||" . join($DCOL, map { " '''$_''' " } @totales_medallero) . "\n";
$medallero_wiki .= "|}\n\n";

say $medallero_wiki if $DEBUG == 2;

## 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 

say $página_wiki if $DEBUG == 2;

# Editamos la página
$página_wiki = $medallero_wiki;
#if ($página_wiki =~ s/^=+Medallero=+\K.+?(?=^=)/\n$medallero_wiki/sm) {
    say $página_wiki if $DEBUG == 2;

    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';
#}

__END__