【问题标题】:How to manipulate a DOM element while running a perl mechanize script?如何在运行 perl 机械化脚本时操作 DOM 元素?
【发布时间】:2012-04-12 15:53:35
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 你指的是哪个 DOM?谁在查看这些页面?您是否在 Web 应用程序中使用 WWW::Mechanize?您是否向用户显示正在检索的页面?
  • 我很惊讶有人 +1 @reinerpost。编程中没有“直觉”吗?那么其他人如何完美地理解该帖子?一篇好文章的目标不就是简短而简洁吗?正确使用“假设”可以减轻冗长的解释,从而节省每个人的时间,以便真正需要用非显而易见的事实来构建概念。或者,我只是在浪费理论细节(没有朋友认为我值得一提)?
  • 显然,两个人不明白。至少其中一个仍然没有。
  • 你是对的,@reinierpost。我会尝试更正我的帖子。谢谢。
  • 显示刮板的代码,以便人们可以看到计算进度的适当方法是什么。

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


【解决方案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>~]
        ]
    }
};

【讨论】:

  • 你好@daxim。你又一次给了我难以置信的建议。我一直在阅读您的原始帖子,现在您的“编辑:代码示例”很棒。我只是需要一些时间来研究它。非常感谢!我将(暂时)关闭绿色复选标记只是为了征求其他意见——尽管似乎没有人能很好地解决问题。感谢您分享您的知识!
  • 我一直在阅读有关使用 jQuery 进行轮询的教程。回到您的示例,这似乎超出了我的想象。我不是在下载文件,而是在执行一系列步骤。
  • 天啊,@daxim,你刚刚丢给我的密集代码。 :) 我一直在阅读这些模块,但我只是乞求得到这个想法。您能对这里发生的事情进行书面概述吗?
  • 我看到了 jQuery。 DBI 数据库如何连接(一个 tmp 文件被用作平面 [意味着文本文件] 数据库吗?)和 Plack:Request 的 if ('/progress' eq $req->path_info) 与以下行相关:$dbh ->do('从进度中删除'); $dbh->do('插入进度(progress)值(0)');感谢您的帮助!
  • SQLite 不是临时文件或文本文件,而是真正的数据库。 connect in DBI 返回一个数据库句柄以使用 SQL 语句进行操作。如果您以前没有见过数据库接口,请阅读DBI book。如果您不知道,请学习 SQL 基础知识。 - Plack::Request 根本与此无关。它的目的是根据 HTTP 请求进行路由:简单地区分是返回 Ajax 的进度号,还是在后台启动下载并返回主 HTML 文档。
猜你喜欢
  • 2013-10-16
  • 1970-01-01
  • 1970-01-01
  • 2016-08-20
  • 2011-06-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
相关资源
最近更新 更多