• Publicidad

Problema en bajar fichero de una web

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Problema en bajar fichero de una web

Notapor enric73 » 2012-04-28 04:15 @219

Hola compañeros, tengo un problema.

Estoy haciendo un programa para bajarme de forma automática unos ficheros de una web. Si lo ejecuto directamente desde el shell con curl, me descarga el fichero sin problemas:

Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. $ curl "http://nomads.ncep.noaa.gov/cgi-bin/filter_gfs.pl?file=gfs.t00z.pgrbf00.grib2&lev_10_m_above_ground=on&var_UGRD=on&var_VGRD=on&subregion=&leftlon=-20&rightlon=20&toplat=40&bottomlat=20&dir=%2Fgfs.2012042800" -o myfile
  2.   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
  3.                                  Dload  Upload   Total   Spent    Left  Speed
  4. 101  2942    0  2942    0     0   2268      0 --:--:--  0:00:01 --:--:-- 12057
Coloreado en 0.005 segundos, usando GeSHi 1.0.8.4


Pero con el siguiente fichero perl no lo consigo... ¿algún consejo? ¿Diría que por el mensaje me falta descargar el módulo de curl? Me sale el mensaje inferior, después del script.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl -w
  2. # ************************************************************************** #
  3. # Script para bajar ficheros de una web                                      #
  4. # ************************************************************************** #
  5.  
  6.  
  7. # ----------------------------------------------------------------------------
  8. # Directoris
  9. # ----------------------------------------------------------------------------
  10.  
  11. $homeWWW3     = '/home/enric/opt';
  12. $DadesGribWWW3   = "$homeWWW3/gribs";
  13.  
  14.  
  15. # ----------------------------------------------------------------------------
  16. # Arguments del programa: data [yyyymmdd]hh
  17. # ----------------------------------------------------------------------------
  18.  
  19. my $date = shift;
  20.  
  21. if (not defined $date  or  $date!~ /^\d{8,10}$/) {
  22.     print "Us del programa:  $0 yyyymmdd[hh]\n";
  23.     print "Ex:               $0 2012042700\n";
  24.  
  25.     exit 1;
  26. }
  27.  
  28.  
  29.  
  30. # ----------------------------------------------------------------------------
  31. # Creamos el directorio para descargas de los grib
  32. # ----------------------------------------------------------------------------
  33.  
  34. $Datos_grib   = "$DadesGribWWW3/$date";
  35.  
  36.         escriu("Creando datos");
  37.         mkdir("$Datos_grib")or warn $!;
  38.  
  39. {
  40.         chdir("$Datos_grib");
  41.        
  42. }
  43.  
  44. # ----------------------------------------------------------------------------
  45. # Bajada ficheros
  46. # # ----------------------------------------------------------------------------
  47.  
  48.  
  49. #$curl="curl";
  50. # grib2 files del  operational nomads server
  51. # #
  52. # #
  53.  
  54. @args = ("curl "http://nomads.ncep.noaa.gov/cgi-bin/filter_gfs.pl?file=gfs.t00z.pgrbf00.grib2&lev_10_m_above_ground=on&var_UGRD=on&var_VGRD=on&subregion=&leftlon=-20&rightlon=20&toplat=40&bottomlat=20&dir=%2Fgfs.2012042800" -o mygrib");
  55. system(@args) == 0 or die "system @args failed: $?";
  56.  
  57.  
  58.  
  59. sub escriu
  60. {
  61.         my @missatge = @_;
  62.         chomp (my $hora = `date |awk '{print \$4}'`);
  63.         print "----->  $hora @missatge\n";
  64. }
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4


Mensaje de error al ejecutar el script:

Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. $ ./Get_gfs_control_dominis.pl 2012042800Can't locate WWW/Curl.pm in @INC (@INC contains: /usr/local/lib64/perl5/site_perl/5.10.0/x86_64-linux-thread-multi /usr/local/lib/perl5/site_perl/5.10.0 /usr/lib64/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi /usr/lib/perl5/vendor_perl/5.10.0 /usr/lib/perl5/vendor_perl /usr/lib64/perl5/5.10.0/x86_64-linux-thread-multi /usr/lib/perl5/5.10.0 /usr/lib/perl5/site_perl .) at ./Get_gfs_control_dominis.pl line 17.
  2. BEGIN failed--compilation aborted at ./Get_gfs_control_dominis.pl line 17 (#1)
  3.    (F) You said to do (or require, or use) a file that couldn't be
  4.     found. Perl looks for the file in all the locations mentioned in @INC,
  5.     unless the file name included the full path to the file.  Perhaps you
  6.     need to set the PERL5LIB or PERL5OPT environment variable to say where
  7.     the extra library is, or maybe the script needs to add the library name
  8.     to @INC.  Or maybe you just misspelled the name of the file.  See
  9.     perlfunc/require and lib.
  10.    
  11. Uncaught exception from user code:
  12.         Can't locate WWW/Curl.pm in @INC (@INC contains: /usr/local/lib64/perl5/site_perl/5.10.0/x86_64-linux-thread-multi /usr/local/lib/perl5/site_perl/5.10.0 /usr/lib64/perl5/vendor_perl/5.10.0/x86_64-linux-thread-multi /usr/lib/perl5/vendor_perl/5.10.0 /usr/lib/perl5/vendor_perl /usr/lib64/perl5/5.10.0/x86_64-linux-thread-multi /usr/lib/perl5/5.10.0 /usr/lib/perl5/site_perl .) at ./Get_gfs_control_dominis.pl line 17.
  13. BEGIN failed--compilation aborted at ./Get_gfs_control_dominis.pl line 17.
  14. at ./Get_gfs_control_dominis.pl line 17
  15.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Supongo que he de cargar el módulo de Curl, ¿cuál es, exactamente? Muchas gracias y buen fin de semana.
enric73
Perlero nuevo
Perlero nuevo
 
Mensajes: 154
Registrado: 2012-03-16 06:27 @311

Publicidad

Re: Problema en bajar fichero de una web

Notapor explorer » 2012-04-28 05:06 @254

Necesitas aprender más Perl ;)

Con Perl, no necesitas llamar a buena parte de los comandos externos, como date, curl o awk. Todo lo puedes realizar con el propio Perl. Si no lo haces, es lo mismo como si programaras un script de shell. Igual que usar un tanque para ir a hacer la compra :lol: (casi mejor, entonces, hacerlo en shell)

Ejemplo: para conseguir la hora, te vale con esto:

my $hora = (split" ", scalar localtime)[3];

Bueno, está muy compactado, pero lo principal es saber que existe la función interna localtime().

El problema que tienes es que has escrito mal las comillas. Es mejor que pongas todo el comando dentro de comillas simples.

Para instalarte módulos, depende del sistema operativo y versión del Perl que tengas.

Desde Perl, la solución es más clara:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.14;
  3. use URI::Escape;
  4.  
  5. my $host = 'http://nomads.ncep.noaa.gov';
  6. my $cgi  = 'cgi-bin/filter_gfs.pl';
  7. my %args = (
  8.     file                  => 'gfs.t00z.pgrbf00.grib2',
  9.     lev_10_m_above_ground => 'on',
  10.     var_UGRD              => 'on',
  11.     var_VGRD              => 'on',
  12.     subregion             => '',
  13.     leftlon               => -20,
  14.     rightlon              =>  20,
  15.     toplat                =>  40,
  16.     bottomlat             =>  20,
  17.     dir                   =>  '/gfs.2012042800',
  18. );
  19.  
  20. my $URL = "$host/$cgi" . '?' . join "&", map { $_ . '=' . uri_escape($args{$_}) } keys %args;
  21.  
  22. say "[$URL]";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Fíjate: son muchas líneas, pero están escritas de tal manera que nos sería muy sencillo cambiar los argumentos, si tuviéramos que hacerlo.

Incluso, solo le faltan un par de líneas para hacer un bucle y bajar archivos todos los días de forma automática. Ejemplo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use DateTime;
  2. my $date = DateTime->now->ymd("");  # yyyymmdd de ahora mismo
  3. ...;
  4. $args{'dir'} = "/gfs.${date}00";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Otra ventaja es que, con unos cambios mínimos, podemos usar la fecha y hora GMT (algo muy importante si estamos trabajando con este tipo de información).

Incluso la construcción del $URL parece muy complicada, pero... solo hay que escribirla una vez, y nos aleja del problema de acordarnos de escribir los caracteres '?' y '&'. E importante es que nos "escape" los caracteres extraños (como la '/' del argumento 'dir') con la función uri_escape().

Ya solo queda bajar el archivo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use LWP::Simple;
  2. mirror($URL, 'mygrib');
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Naturalmente, hay que poner más controles, por si se corta la conexión, comprobar el estado del archivo, etc.

¡Qué tiempos! ¡Yo hacía todo esto hace ahora diez años, en el LATUV! (¿No tenéis un puesto de trabajo para mi? :oops: )
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problema en bajar fichero de una web

Notapor enric73 » 2012-04-28 06:36 @316

¡Hola, explorer! Muchas gracias. Sí, he de aprender más Perl. Estoy más acostumbrado a manejar shell... Hay una empresa que está muy metida en temas de meteo y es muy técnica, un perfil como el tuyo encajaría perfectamente (http://www.meteosim.com).

Voy a mirarme bien el código porque ¡seguro que tengo dudas! Hasta luego.
enric73
Perlero nuevo
Perlero nuevo
 
Mensajes: 154
Registrado: 2012-03-16 06:27 @311

Re: Problema en bajar fichero de una web

Notapor enric73 » 2012-04-29 15:48 @700

Hola explorer.

Lo he automatizado de la siguiente manera:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.10;
  3. use URI::Escape;
  4. use LWP::Simple;
  5. use DateTime;
  6.  
  7. $Gribs_gfs = '/home/enric/v2.22/gribs/';
  8.  
  9. my $date = DateTime->now->ymd("");
  10.  
  11. mkdir("$Gribs_gfs/${date}00") or warn $!;
  12.  
  13. escriu("Creando carpeta para descargar los ficheros GFS por fecha");
  14.  
  15. @files
  16.     = qw( gfs.t00z.pgrbf00.grib2 gfs.t00z.pgrbf03.grib2 gfs.t00z.pgrbf06.grib2 gfs.t00z.pgrbf09.grib2    gfs.t00z.pgrbf12.grib2 gfs.t00z.pgrbf15.grib2 gfs.t00z.pgrbf18.grib2 gfs.t00z.pgrbf21.grib2 gfs.t00z.pgrbf24.grib2    gfs.t00z.pgrbf27.grib2 gfs.t00z.pgrbf30.grib2 gfs.t00z.pgrbf33.grib2 gfs.t00z.pgrbf36.grib2 gfs.t00z.pgrbf39.grib2    gfs.t00z.pgrbf42.grib2 gfs.t00z.pgrbf45.grib2 gfs.t00z.pgrbf48.grib2 );
  17.  
  18. $data           = '00';
  19. $interval_hours = 3;
  20.  
  21. for ( @files[ 0 .. 16 ] ) {
  22.  
  23.     $Gribs_Date = "$Gribs_gfs/${date}00/mygrib$data";
  24.     my $host = 'http://nomads.ncep.noaa.gov';
  25.     my $cgi  = 'cgi-bin/filter_gfs.pl';
  26.     my %args = (
  27.         file                  => $_,                   # 'gfs.t00z.pgrbf06.grib2',
  28.         lev_10_m_above_ground => 'on',
  29.         var_UGRD              => 'on',
  30.         var_VGRD              => 'on',
  31.         subregion             => '',
  32.         leftlon               => -30,
  33.         rightlon              => -10,
  34.         toplat                => 40,
  35.         bottomlat             => 20,
  36.         dir                   => "/gfs.${date}00",
  37.     );
  38.  
  39.     my $URL = "$host/$cgi" . '?' . join "&", map { $_ . '=' . uri_escape( $args{$_} ) } keys %args;
  40.  
  41.     say "[$URL]";
  42.  
  43.     #   mirror ($URL, 'mygrib');
  44.  
  45.     mirror( $URL, $Gribs_Date );
  46.  
  47.     $data = sprintf "%02d", $data + $interval_hours;
  48. }
  49.  
  50. sub escriu {
  51.     my @missatge = @_;
  52.     chomp( my $hora = `date |awk '{print \$4}'` );
  53.     print "------>  $hora @missatge\n";
  54. }
  55.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


¿Hay alguna manera para no tener que introducir todos los nombres de los ficheros que me interesa descargar?
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
@files = qw( gfs.t00z.pgrbf00.grib2 gfs.t00z.pgrbf03.grib2 gfs.t00z.pgrbf06.grib2 gfs.t00z.pgrbf09.grib2    gfs.t00z.pgrbf12.grib2 gfs.t00z.pgrbf15.grib2 gfs.t00z.pgrbf18.grib2 gfs.t00z.pgrbf21.grib2 gfs.t00z.pgrbf24.grib2    gfs.t00z.pgrbf27.grib2 gfs.t00z.pgrbf30.grib2 gfs.t00z.pgrbf33.grib2 gfs.t00z.pgrbf36.grib2 gfs.t00z.pgrbf39.grib2    gfs.t00z.pgrbf42.grib2 gfs.t00z.pgrbf45.grib2 gfs.t00z.pgrbf48.grib2 );
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Otra consulta, sobre
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. map { $_ . '='. uri_escape($args{$_}) } keys %args
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Exactamente, ¿qué hace?

De esta manera es mucho mas cómodo si uno quiere modificar el dominio en lat/lon...

Muchas gracias.
enric73
Perlero nuevo
Perlero nuevo
 
Mensajes: 154
Registrado: 2012-03-16 06:27 @311

Re: Problema en bajar fichero de una web

Notapor explorer » 2012-04-29 16:22 @724

Quitas las líneas 15 y 16, y modificas el for de la 21, por
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for my $i ( 0 .. 16 ) {
  2.     $_ = sprintf "gfs.t00z.pgrbf%02d.grib2", $i * 3;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
map { $_ . '='. uri_escape($args{$_}) } keys %args
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Esta línea, lo que hace, es sacar las claves (keys) de %args (inicializado en la línea 26). Así, tenemos una lista de elementos como esta: 'file', 'lev_10_m_above_ground', 'var_UGRD', 'var_VGRD', 'subregion', 'leftlon'...

Esa lista entra en el map{}. Cada valor se "mete" en la variable por defecto $_.

Lo que hace map{} es ejecutar un trozo de código por cada valor de la lista de elementos. Así, para 'file', ejecuta: 'file' . '=' . uri_escape($args{'file'}) .

$args{'file'} es el valor correspondiente a la clave 'file' (el nombre del archivo gfs.t00z... ). Eso se lo pasamos a uri_escape(), cuya misión es "escapar" los caracteres para que puedan ser incluidos dentro de una URL (por ejemplo, el carácter '/' se convierte en '%2F').

El resultado del map{} es una lista de cadenas de texto, así: 'file=gfs.t00z.pgrbf00.grib2', 'var_UGRD=on', 'toplat=40'...

Luego, el join() se encargará de unirlas todas con caracteres '&'.

¡Artesanía pura, oiga! ( <= quiere decir que en Perl, se puede hacer de otra forma, más cómoda)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problema en bajar fichero de una web

Notapor enric73 » 2012-04-29 16:50 @743

Buenas noches, explorer. ¡Gracias por la explicación sobre map{} y por lo del for! ¡Como dice, arte! Hasta pronto.
enric73
Perlero nuevo
Perlero nuevo
 
Mensajes: 154
Registrado: 2012-03-16 06:27 @311


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 16 invitados