Página 1 de 1

Problema en bajar fichero de una web

NotaPublicado: 2012-04-28 04:15 @219
por enric73
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.004 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.003 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.

Re: Problema en bajar fichero de una web

NotaPublicado: 2012-04-28 05:06 @254
por explorer
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: )

Re: Problema en bajar fichero de una web

NotaPublicado: 2012-04-28 06:36 @316
por enric73
¡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.

Re: Problema en bajar fichero de una web

NotaPublicado: 2012-04-29 15:48 @700
por enric73
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.

Re: Problema en bajar fichero de una web

NotaPublicado: 2012-04-29 16:22 @724
por explorer
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)

Re: Problema en bajar fichero de una web

NotaPublicado: 2012-04-29 16:50 @743
por enric73
Buenas noches, explorer. ¡Gracias por la explicación sobre map{} y por lo del for! ¡Como dice, arte! Hasta pronto.