Usuario:JoaquinFerrero/MedalleroMoscu2013

Programa para la actualización automática del Medallero de los Campeonato Mundial de Atletismo de 2013

editar
#!/usr/bin/env perl
#
# medalleroMoscu2013.pl
#
# Autor:
#       Joaquín Ferrero
#
# Descripción:
#       Actualización automática de medalleros olímpicos en Wikipedia.
#
# Entrada: ninguna
# Salida:  ninguna
#
# Historial:
#   2013.08.13 : 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.iaaf.org/competitions/iaaf-world-championships/14th-iaaf-world-championships-4873/medaltable';
my $WIKIPEDIA_PÁGINA_MEDALLERO  = 'Campeonato Mundial de Atletismo de 2013';
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 $DEBUG                       =  1;                                   # 0 o 1
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 15 min. durante el periodo de los juegos.

            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 $medallero_html;

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

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

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

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

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 (@filas) {
    my $resultados;                                                     # resultados para un participante

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

    $celdas[1]->children->first->attrs('src')
        =~ /(\w+)[.](?:gif|png)$/;                                      # extraemos el código COI de la bandera
    $resultados->{'COI'} = uc $1;

    my @medallas;
    for my $celda (@celdas[2 .. 5]) {                                   # resto de celdas de la fila: número de medallas
        push @medallas, 0+ $celda->text;
    }
    $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 = ' || ';
for my $fila (@tabla_medallero_oficial) {
    my @medallas = @{$fila->{'medallas'}};                                              # Número de 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";
}

# 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;
    }
}
else {
    die 'ERROR: no encuentro la sección del medallero en la página';
}

__END__