如何在运行perl mechanize脚本时操作DOM元素?

时间:2012-04-12 15:53:35

标签: javascript perl progress-bar perl-module www-mechanize

This post讨论了如何通过计算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数据库。我将以php形式显示收集的内容,供用户在Perl脚本完成后保存。收集过程从10秒到1分钟不等。我想显示进度,因为脚本导航用户的帐户页面收集信息。

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

如果所有这些都需要多个DOM,分支进程并将控制从一个脚本执行返回到另一个...那么我绝对是我的头脑。但是,我想学习它。 :)我将非常感谢您阅读和学习的内容。如果它实际上比我意识到的要简单得多,那么我也会很感激。

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

答案: 回顾:对我来说,我决定假设显示进度的进度条,估计它需要的时间。这很好用。 This post显示了如何将perl脚本的输出复制回调用php脚本,但随后将该信息反馈给原始DOM变得过于复杂而不值得。通过传递给perl脚本的各种参数使其更加复杂,这改变了进度和输出。 “假装”证明是一个很好的解决方案。嘿,现在我知道为什么我的女朋友会这样做! :)

PS。我给了daxim一个绿色的复选标记,因为他已经回答了我的其他问题,对我来说是一个很大的帮助,即使他在这个问题上有点在黑暗中射击。

1 个答案:

答案 0 :(得分: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>~]
        ]
    }
};