você está aqui: Home  → Arquivo de Mensagens Curso Gratuito sobre Expressões Regulares, com o Prof.  Julio Neves

Rastreando pedidos no site dos Correios com Perl

Colaboração: Fernando Henrique Giorgetti

Data de Publicação: 14 de junho de 2011

Escrevi um script perl para acompanhamento de códigos de rastreio junto ao site dos correios. Ele mantém uma lista dos tracking numbers buscados, até que eles tenham sido entregues.

Seu uso é bem simples, basicamente:

./correios.pl

TRACKINGNUMBER1 TRACKINGNUMBER2 ... TRACKINGNUMBERN

Uma vez executado, os códigos solicitados via linha de comando ficam armazenados num arquivo para futuras consultas. O script buscará pelos códigos armazenados no histórico e por todos os demais, passado por parâmetro (caso existam).

Exemplos:

[fernando@localhost correios]$ ./correios.pl

ES720931075BR
State for all tracking numbers

TRACKING NUMBER    | DATE             | STATUS
ES720931075BR      | 24/05/2011 20:27 | ACF TRES AVENIDAS - LIMEIRA /SP Encaminhado
                                      Em trânsito para CTE CAMPINAS - VALINHOS/SP

O código acima, continuará armazenado e será buscado automaticamente, até que tenha sido entregue.

Supondo que agora eu queira buscar um outro tracking number, só será necessário informar o novo código, exemplo:

[fernando@localhost correios]$ ./correios.pl

ES696088008BR
Previous state for stored tracking numbers
TRACKING NUMBER    | DATE             | STATUS
ES720931075BR      | 24/05/2011 20:27 | ACF TRES AVENIDAS - LIMEIRA /SP Encaminhado
                                      Em trânsito para CTE CAMPINAS - VALINHOS/SP

State for all tracking numbers
TRACKING NUMBER    | DATE             | STATUS
ES696088008BR      | 11/03/2011 18:03 | CEE LIMEIRA - LIMEIRA/SP        Entregue
ES720931075BR      | 24/05/2011 20:27 | ACF TRES AVENIDAS - LIMEIRA /SP Encaminhado
                                      Em trânsito para CTE CAMPINAS - VALINHOS/SP

Note que ele buscou o anterior (pois ainda não está marcado como "Entregue") e buscou o novo ES696088008BR. Esse último já foi entregue, portanto não será armazenado para futuras consultas, exemplo:

[fernando@localhost correios]$ ./correios.pl

Previous state for stored tracking numbers
TRACKING NUMBER    | DATE             | STATUS
ES720931075BR      | 24/05/2011 20:27 | ACF TRES AVENIDAS - LIMEIRA /SP Encaminhado
                                      Em trânsito para CTE CAMPINAS - VALINHOS/SP

State for all tracking numbers
TRACKING NUMBER    | DATE             | STATUS
ES720931075BR      | 24/05/2011 20:27 | ACF TRES AVENIDAS - LIMEIRA /SP Encaminhado
                                      Em trânsito para CTE CAMPINAS - VALINHOS/SP

Segue o código fonte (download do código)

#!/usr/bin/perl

#
# Author: Fernando H Giorgetti < fgiorgetti@gmail.com>
# Date  : 08/27/2010
#
# Description:  Provides a friendly interface for tracking packages
#               by keeping a list of all requested tracking numbers
#              till they have been delivered
#
#               It only works with brazilian tracking numbers (thru the Correios website)
#

# Libraries
use POSIX qw(strftime);
use Env qw(HOME);

#
# General configuration
#

# Tracking numbers datafile
$DATAFILE="$HOME/tracking_numbers.dat";

# Flag that indicates whether to remove tracking numbers once delivered
$REMOVE_COMPLETED=1;

# Remove Tracking numbers that have no results (invalid not yet available)
$REMOVE_NORESULTS=0;

# State that indicates whether a package has been delivered
$COMPLETED_STATE="Entregue";

# URL for the Correios website
$URL="http://websro.correios.com.br/sro_bin/txect01\$.QueryList?P_LINGUA=001&P_TIPO=001&P_COD_UNI=

";

# Website output header (used to determine where relevant content starts)
$HEADER="Data .*Local .*Situa";

# Results header (Used when showing overall results)
$RESULTSHEADER="TRACKING NUMBER    | DATE             | STATUS\n";

# End of statuses string
$ENDOFSTATUSES="____________________________________";

#
# Validate whether return code matches the expected code
# and in case it does not match, show the error message and terminate
#
sub validateReturnCode {

      $code = $_;
      $expected = $_;
      $msg = $_;

      if ( $code != $expected ) {
              printf "%s\n", $msg;
              exit $code;
      }

}

#
# Tries to create the DAT file
# In case an error occurs, show an error message then exit
#
sub createDataFile {

      if ( ! -f $DATAFILE ) {
              system(touch, "$DATAFILE");
              validateReturnCode("$?", "0", "Error creating $DATAFILE");
      }

}

sub printTrackingNumberInfo {

      $trackingNumber = shift(@_);
      $date = shift(@_);
      $status = shift(@_);
      $status =~ s/< BR>/\n                                        /g;

      printf "%-18s | %s | %s\n", $trackingNumber, $date , $status;

}

#
# Dumps the website and searches for the given tracking number's last status
#
sub dumpWebsite {

      # Reading given tracking number
      $TRACKINGNUMBER = shift(@_);

      # Dumping the website
      open(IN, "lynx -dump \"$URL$TRACKINGNUMBER\" |");

      # Reading content
      @data = < IN>;

      # Closing input
      close(IN);

      # Cleaning the status
      $date = strftime("%m/%d/%Y %H:%M", localtime);
      $STATUS = "";

      # Parsing response content
      $found = 0;
      if ( ! (grep {/$HEADER/} @data ) ) {
              $STATUS = "No data has been found";
      } else {

              # Found the header, proceeding
              foreach $line (@data) {
                      # Found the right line
                      if ($found == 1) {
                              chomp($line);
                              if ( $line =~ /([0-9]{2}\/[0-9]{2}\/[0-9]{4} [0-9]{2}:[0-9]{2})[ ]+(.*$)/ ) {
                                      # Found the 2nd latest status entry, time to skip
                                      if ($firstFound == 1) {
                                              last;
                                      }
                                      $date = $1;
                                      $STATUS = $2;
                                      $firstFound = 1;
                              } else {
                                      # Found the deadline
                                      if ( $line =~ /$ENDOFSTATUSES/ ) {
                                              last;
                                      }

                                      # Appending further lines to the status message
                                      $line =~ s/^\s+//;
                                      $STATUS .= sprintf("< BR>%s", $line);
                              }
                      }

                      # Found the header, mark found = 1 to read next line and skip
                      if ( $line =~ /$HEADER/ ) {
                              $found = 1;
                              $firstFound = 0;
                              next;
                      }
              }

      }

      # Displaying current status for given Tracking number
      printTrackingNumberInfo($TRACKINGNUMBER, $date , $STATUS);
      $LIST{$TRACKINGNUMBER}{status}="$STATUS";
      $LIST{$TRACKINGNUMBER}{date}="$date";

      # If STATUS means delivered and REMOVE_COMPLETED = 1, remove the tracking number from the list
      if (    ( $REMOVE_COMPLETED == 1 && $STATUS =~ /$COMPLETED_STATE$/ ) ||
              ( $REMOVE_NORESULTS && $found == 0) ) {
              delete $LIST{$TRACKINGNUMBER}{status};
              delete $LIST{$TRACKINGNUMBER}{date};
              delete $LIST{$TRACKINGNUMBER};
      }

}

#
# Add all valid tracking numbers to the hash named LIST
#
sub pushTrackingNumbers {

      # Loop through all given tracking numbers
      foreach $trackingNumber (@_) {

              # Sanity check
              if ( $trackingNumber !~ /[A-Z0-9]+/ ) {
                      printf "Invalid tracking number: %s\n", $trackingNumber;
                      next;
              }

              # Add to the hash
              $LIST{$trackingNumber}{status} = "";
              $LIST{$trackingNumber}{date} = "";

      }

}

#
# Serializes the active list of tracking numbers
#
sub serializeActiveList {

      # Opening output file
      open(OUT, ">$DATAFILE") or die "Could not open $DATAFILE";

      # Saving all tracking numbers and current status
      foreach $key (sort keys %LIST) {
              printf OUT "%s;%s;%s\n", $key, $LIST{$key}{date}, $LIST{$key}{status};
      }

      # Closing output file
      close(OUT);
}

#
# Main Code
#

# Validating if lynx is installed
open(LYNX, "lynx -version |") or die "Lynx must be installed! Exiting.";
close(LYNX);

# Hash of active tracking numbers
%LIST = ();

# Reading input tracking numbers
pushTrackingNumbers(@ARGV);

# Reading DAT file list and pushing to the LIST
open(DATA, "<$DATAFILE");
@LINES=< DATA>;
close(DATA);

# If there are stored tracking numbers, show a header
if (scalar(@LINES) > 0) {
      printf "Previous state for stored tracking numbers\n";
      printf "%s", $RESULTSHEADER;
}

# Pushing stored tracking numbers to STORED array
@STORED;
foreach $line (@LINES) {
      if ( $line =~ /([A-Z0-9]+);(.*);(.*)/ ) {
              printTrackingNumberInfo($1, $2, $3);
              push(@STORED, "$1");
      }
}

pushTrackingNumbers(@STORED);
printf "\n" if (scalar(@STORED) > 0);

# Dumping the website for all valid tracking numbers
if (scalar(keys %LIST) > 0) {
      printf "State for all tracking numbers\n";
      printf "%s", $RESULTSHEADER;

      foreach $trackingNumber (sort keys %LIST) {
              dumpWebsite($trackingNumber);
      }
}

# Saving the datafile
serializeActiveList;

Acredito que possa ser útil pra mais gente, pois pra mim é muito útil :)



Veja a relação completa dos artigos de Fernando Henrique Giorgetti