2016-06-29 7 views
1

Dies ist meine erste Frage, also entschuldige ich mich im Voraus, wenn ich alles falsch formatiere/frage.Verwenden Sie Try und Catch, um vergangene Fehler zu verschieben

Ich verwende Perl, um eine Zeichenfolge aus einer Datei zu extrahieren, ein Webformular zu senden und eine neue Datei herunterzuladen, die von der Webseite erstellt wurde. Das Ziel ist es, es für 30.000 Dateien in einer Schleife laufen zu lassen, was schätzungsweise ~ 8 Tage dauert. Ich verwende WWW :: Selenium und WWW :: Mechanize, um die Webautomatisierung durchzuführen. Das Problem, das ich habe, ist, dass, wenn aus irgendeinem Grund eine Seite nicht richtig lädt oder das Internet für eine gewisse Zeit abfällt, das Skript beendet wird und eine Fehlermeldung gibt (je nachdem, in welcher Stufe es fehlgeschlagen ist):

Error requesting http://localhost:4444/selenium-server/driver/: 
ERROR: Could not find element attribute: link=Download PDB [email protected] 

Ich möchte, dass das Skript weiterläuft und in die nächste Runde der Schleife geht, damit ich mir keine Sorgen machen muss, wenn eine einzelne Runde der Schleife einen Fehler verursacht. Meine Forschung schlägt vor, dass die Verwendung Try::Tiny die beste Lösung sein kann. Derzeit habe ich das Skript unten nur mit try{...}, die scheint, jeden Fehler zu unterdrücken und das Skript durch die Dateien fortzusetzen. Ich bin jedoch besorgt, dass dies eine sehr unverblümte Lösung zu sein scheint und mir keinen Einblick gibt, in welche/warum Dateien fehlgeschlagen sind.

Idealerweise würde ich den Dateinamen und die Fehlermeldung für jedes Vorkommen zu einer anderen Datei drucken, die dann überprüft werden kann, sobald das Skript abgeschlossen ist, aber ich habe Schwierigkeiten zu verstehen, wie man catch{...} dies tut oder wenn das ist richtige Lösung.

use strict; 
use warnings; 
use WWW::Selenium; 
use WWW::Mechanize; 
use Try::Tiny; 


my @fastas = <*.fasta>; 
foreach my $file (@fastas) { 
try{ 

open(my $fh, "<", $file); 
my $sequence; 
my $id = substr($file, 0, -6); 
while (my $line = <$fh>) { 

     ## discard fasta header line 
     } elsif($line =~ /^>/) {  #/(turn off wrong coloring) 
      next; 

     ## keep line, add to sequence string 
     } else { 
      $sequence .= $line; 
     } 
    } 
close ($fh); 

my $sel = WWW::Selenium->new(host => "localhost", 
           port => 4444, 
           browser => "*firefox", 
           browser_url => "http://www.myurl.com", 
          ); 

$sel->start; 
$sel->open("http://www.myurl.com"); 
$sel->type("chain1", $sequence); 
$sel->type("chain2", "EVQLVESGPGLVQPGKSLRLSCVASGFTFSGYGMHWVRQAPGKGLEWIALIIYDESNKYYADSVKGRFTISRDNSKNTLYLQMSSLRAEDTAVFYCAKVKFYDPTAPNDYWGQGTLVTVSS"); 
$sel->click("css=input.btn.btn-success"); 
$sel->wait_for_page_to_load("30000"); 

## Wait through the holding page - will timeout after 5 mins 
$sel->wait_for_element_present("link=Download PDB File", "300000"); 
## Get the filename part of link 
$sel->wait_for_page_to_load("30000"); 
my $pdbName = $sel->get_attribute("link=Download PDB File\@href"); 
## Concatenate it with the main domain 
my $link = "http://www.myurl.com/" . $pdbName; 
$sel->stop; 

my $mech = WWW::Mechanize->new(autocheck => 1); 
$mech -> get($link); 
#print $mech -> content(); 
$mech -> save_content($id . ".pdb"); 
}; 

} 
+3

Ihr Code sieht fehlerhaft aus, zum Beispiel die Zeile} elsif ($ line = ~/^> \ /) {. Überprüfen Sie bitte Ihren geposteten Code. – wolfrevokcats

+0

Ja, mir ist dieser Backslash bekannt. Ohne es ging die Formatierung auf dieser Seite drunter und drüber, ich konnte nicht herausfinden warum, aber es ist nicht in meinem eigentlichen Code. – PerlPingu

+1

Ich sympathisiere damit! Ich habe Ihren Beitrag bearbeitet, um den Fehler zu korrigieren und weitere falsche Farben durch den Editor zu unterdrücken. Sie können dies tun, indem Sie einen weiteren Schrägstrich in einem Kommentar in derselben Zeile, '# /', hinzufügen. Ich fügte auch eine Aussage (in diesem Kommentar) hinzu, wofür es ist. Wenn Ihnen das nicht gefällt, bitte ändern Sie es auf alle Fälle. (Aber Sie wollen nicht Code, der falsch ist, egal, das Format.) – zdim

Antwort

4

Sie haben völlig Recht, dass Sie alle Fehler (und Warnungen) sehen, protokollieren und überprüfen möchten. Der Mechanismus und die Syntax, die von Try::Tiny bereitgestellt werden, sollen einfach und einfach zu verwenden sein.

use feature qw(say); 

my $errlog = 'error_log.txt'; 
open my $fh_err, '>', $errlog or die "Can't open $errlog for writing: $!"; 

foreach my $file (@fastas) { 
    try { 
     # processing, potentially throwing a die 
    } 
    catch { 
     say $fh_err "Error with $file: $_"; # NOTE, it is $_ (not $! or [email protected]) 
    }; 
} 
close $fh_err; 

# Remove the log if empty 
if (-z $errlog) { 
    say "No errors logged, removing $errlog"; 
    unlink $errlog or warn "Can't unlink $errlog: $!"; 
}  

Sie können Namen von Dateien speichern, für die die Verarbeitung fehlgeschlagen, mit push @failed_files, $file innerhalb des catch { } Block. Dann kann der Code nach der Hauptverarbeitung erneut versuchen, wenn Sie wissen, dass Fehler hauptsächlich auf zufällige Verbindungsprobleme zurückzuführen sind. Und die Liste der fehlgeschlagenen Dateien ist praktisch.

Beachten Sie, dass mit v5.14 die Probleme, die dieses Modul were fixed Adressen, so dass eine normale Verwendung von eval ist in Ordnung. Es ist an dieser Stelle vor allem eine Frage der Präferenz, aber beachte, dass Try::Tiny ein paar eigene Wendungen hat. Eine Diskussion finden Sie unter this post.

Dies betrifft die Frage der einfachen Ausnahmebehandlung, nicht den Rest des Codes.

+0

Danke, das ist genau die Art von Lösung, nach der ich gesucht habe! – PerlPingu

+0

@PerlPingu Großartig :) Sehr froh, das zu hören, danke. – zdim