【问题标题】:Using Try and Catch to move past errors使用 Try and Catch 移动过去的错误
【发布时间】:2016-06-29 18:03:45
【问题描述】:

这是我的第一个问题,所以如果我格式化/问错了,我提前道歉。

我正在使用 Perl 从文件中提取字符串、提交 Web 表单并下载由网页创建的新文件。目标是让它循环运行 30,000 个文件,我估计这需要大约 8 天。我正在使用 WWW::Selenium 和 WWW::Mechanize 来执行网络自动化。我遇到的问题是,如果由于某种原因页面无法正确加载或互联网中断一段时间,则脚本退出并给出错误消息,例如(取决于它在哪个阶段失败):

Error requesting http://localhost:4444/selenium-server/driver/:
ERROR: Could not find element attribute: link=Download PDB File@href

我希望脚本继续运行,进入下一轮循环,因此我不必担心单轮循环是否会引发错误。我的研究表明,使用Try::Tiny 可能是最好的解决方案。目前我有下面的脚本只使用try{...} 这似乎抑制了任何错误并允许脚本继续通过文件。但是我担心这似乎是一个非常生硬的解决方案,并且无法让我了解文件失败的原因/原因。

理想情况下,我希望将每次出现的文件名和错误消息打印到另一个文件,然后在脚本完成后查看该文件,但我很难理解如何使用catch{...} 来执行此操作,或者即使这样正确的解决方案。

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");
};

}

【问题讨论】:

  • 您的代码看起来有问题,例如,行 } elsif($line =~ /^>\/) { 。请检查您发布的代码。
  • 是的,我知道那个反斜杠。没有它,这个网站上的格式就乱套了,我不知道为什么,但它不在我的实际代码中。
  • 我对此表示同情!我已经编辑了您的帖子以纠正错误,并抑制编辑进一步错误的着色。您可以通过在同一行的注释中添加另一个斜杠来做到这一点,# /。我还添加了一个关于它的用途的声明(在那条评论中)。如果你不喜欢这个,请继续改变它,无论如何。 (但无论格式如何,您都不想发布错误的代码。)
  • 啊,谢谢!你知道为什么这会影响颜色吗?
  • 嗯,就是这些斜线(和/或其他特殊符号),无论它们以何种方式配对(或不配对)。我不知道编辑器是如何解析的,但是正则表达式经常会导致这个问题。 (我不确定是否总是 / 会关闭它,但可能是其他的。)它本身也很挑剔 - 它必须是 # / 并且只有在那之后你才能添加文本。

标签: perl


【解决方案1】:

您想查看、记录和查看所有错误(和警告)是完全正确的。 Try::Tiny 提供的机制和语法旨在简单易用。

use warnings;
use strict;
use feature qw(say);
use Try::Tiny;

my @fastas = <*.fasta>;

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 $@)
    };
}
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: $!";
}    

您可以保存处理失败的文件的名称,在 catch { } 块内使用 push @failed_files, $file。然后代码可以在主处理后再次尝试,如果您知道错误主要是由于随机连接问题。并且拥有失败文件的列表很方便。

请注意,在 v5.14 中,此模块解决了were fixed 的问题,因此可以正常使用eval。在这一点上,这主要是一个偏好问题,但请注意Try::Tiny 有它自己的一些曲折。请参阅this post 进行讨论。

这解决了简单异常处理的问题,而不是代码的其余部分。

【讨论】:

  • 谢谢,这正是我正在寻找的解决方案!
  • @PerlPingu 太好了 :) 很高兴听到这个消息,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多