0

这篇文章讨论了如何通过计算 www::mechanize Perl 脚本下载文件的百分比来通过进度条通知用户。

我需要通知我的用户 www::mechanize 脚本的进度,但不一定是剩余百分比。该脚本正在通过用户的帐户进行迁移并获取数据,这些数据的大小可能会有很大差异,因此百分比因子是未知的。

如果我可以通过一些 js DOM div 写入(在 perl 脚本运行时显示“加载器”图像的对话框中)显示“进度”,那么这就足够了。

我可以像这样注入js脚本吗:

<script>
$('#formboxtext').html('Logging into account ...');
</script>

进入 Perl 脚本以向我的用户显示进度?还是必须在更新 DOM 之前返回 Perl 脚本?(答案似乎是“不”。)

我需要 JavaScript::SpiderMonkey 和 WWW::Scripter 模块来实现这一点,还是解决方案更简单?

编辑:

我正在扩展一个基于 PHP 的 CMS。我使用 Perl 和模块 www::Mechanize 编写了一个屏幕抓取脚本,该模块遍历另一个站点上用户帐户的几页以检索到 mySQL 数据库。Perl 脚本完成后,我将以 php 形式显示收集到的内容供用户保存。收集过程从 10 秒到 1 分钟不等。我想在脚本导航收集信息的用户帐户页面时显示进度。

首先,我为用户提供了一个 jQuery 模式对话框(调用一个 php 文件以使用用户名和密码输入的形式填充其内容),用于登录到他们的个人帐户。我在这个对话框中显示了一个加载器图像和一个请求耐心的句子,但我想使用 jQuery 重写这个句子 (div),因为 Perl 脚本在页面中导航,将进度发送回显示;例如,“我现在在这里。现在我在这里。” 如果发生错误(即登录错误),那么我可以重写模式对话框并照常提供解决方案。如果成功,那么我将关闭对话框并在表单输入中显示收集的信息,以便保存到我的数据库中 - 在产生模式对话框的 php 页面上。

如果所有这些都需要多个 DOM、分叉进程并将控制权从一个脚本执行返回到另一个脚本执行……那么我肯定是在我的头上。但是,我想学习它。:) 我将不胜感激有关阅读和学习内容的概述。如果它实际上比我意识到的要简单得多,那么我也会很感激这个答案。

感谢 daxim 和 reinierpost 的耐心和建议。谢谢你的帮助。

答案: 回顾:对我来说,我决定通过估计所需时间来伪造显示进度的进度条。效果很好。这篇文章展示了如何将 perl 脚本的输出复制回调用 php 脚本,但是将这些信息反馈回原始 DOM 变得过于复杂,不值得。由于传递给 perl 脚本的各种参数改变了进程和输出,它变得更加复杂。“伪造它”被证明是一个很好的解决方案。嘿,现在我明白为什么我的女朋友会这样做了!:)

PS。我给 daxim 打了绿色的复选标记,因为他回答了我的其他问题并且对我帮助很大,尽管他在这个问题上有点摸不着头脑。

4

1 回答 1

1

不要像https://stackoverflow.com/a/1938448那样将进度打印到 STDOUT,而是将数字公开为 Web 服务。这应该足够了:

sub {
    return [200, [Content_Type => 'text/plain'], [$PROGRESS]]
}

在客户端,使用jQuery get每隔半秒左右轮询一次 Web 服务,并使用jQuery Progressbar来显示它。


编辑:代码示例

use 5.010;
use strictures;
use DBI qw();
use Plack::Request qw();
use POSIX qw(floor);
use Forks::Super qw(fork);
use WWW::Mechanize qw();

sub db_connect {
    return DBI->connect('dbi:SQLite:dbname=/var/tmp/progress.db');
}

sub {
    my ($env) = @_;
    my $req = Plack::Request->new($env);
    if ('/progress' eq $req->path_info) {
        return [200,
            [Content_Type => 'text/html'],
            [db_connect->selectrow_array('select progress from progress')]
        ]
    } else {
        fork(sub => sub {
            state $total = 0;
            my $dbh = db_connect;
            $dbh->do('delete from progress');
            $dbh->do('insert into progress (progress) values (0)');
            WWW::Mechanize->new->get(
                'http://localhost:5000/VBoxGuestAdditions_4.0.4.iso', # large-ish file
                ':read_size_hint' => 1024**2,
                ':content_cb' => sub {
                    my ($data, $response, $proto) = @_;
                    $total += length($data);
                    my $size = $response->header('Content-Length');
                    $dbh->do(
                        'update progress set progress = ?', {}, floor(($total/$size)*100)
                    );
sleep 1;
                },
            );
        }) unless defined db_connect->selectrow_array('select progress from progress');
        return [200,
            [Content_Type => 'text/html'],
            [q~<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.8.18/themes/base/jquery-ui.css" />
<style>
#progress { width: 80em; height: 5em; border: 1px solid black; }
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script>
<script>
jQuery(document).ready(function() {
    // TODO: stop the timer if progress == 100 or no response
    var timer = setInterval(function() {
        jQuery.ajax({ async: false, cache: false, dataType: 'html', url: 'http://localhost:5001/progress' }).done(function(progress) {
            jQuery('#progress').progressbar({ value: parseInt(progress) });
        });
    }, 500);
});
</script>
</head>
<body>
<h1>downloading your stuff</h1>
<div id="progress"><div>
</body>
</html>~]
        ]
    }
};
于 2012-04-12T16:21:34.507 回答