você está aqui: Home  → Arquivo de Mensagens

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