# HDOJAgent.pm
package HDOJAgent;
use strict;
use warnings;
use LWP::UserAgent;
my $prefix = "http://acm.hdu.edu.cn";
my $interval = 60;
my $maxretry = 2;
sub new {
my $class = shift;
my $self = {
user => $_[0] || '',
problemid => $_[1] || 1000,
language => $_[2] || 0,
ua => new LWP::UserAgent(
agent => 'HDOJAgent (http://watashi.ws/wabots)',
cookie_jar => {},
)
};
bless $self, $class;
return $self;
}
sub AUTOLOAD {
my $self = shift;
my $name = $HDOJAgent::AUTOLOAD;
$name =~ s/.*://;
return if $name eq 'DESTROY';
$self->{$name} = shift if @_;
return $self->{$name};
}
sub post {
my ($self, $url, $form) = @_;
my $ua = $self->ua;
for (1 .. $maxretry) {
my $response = $ua->post($url, $form);
if (!$response->is_error) {
return $response->decoded_content;
}
sleep $interval;
}
warn "maxretry exceeded!";
return undef;
}
sub login {
my ($self, $pass) = @_;
$self->post("$prefix/userloginex.php?action=login", {
username => $self->user,
userpass => $pass,
login => 'Sign In'
});
}
sub submit {
my ($self, $code) = @_;
$self->post("$prefix/submit.php?action=submit", {
problemid => $self->problemid,
language => $self->language,
usercode => $code
});
}
sub laststatus {
my $self = shift;
my $user = $self->user;
while (1) {
my $_ = $self->post("http://acm.hdu.edu.cn/status.php?user=$user");
s{^[\s\S]*Pro\.ID.*Exe\.Time.*Exe\.Memory}{}gs;
s{</td><td><a href="/showproblem\.php\?pid=.*$}{}gs;
s{^.*<td>}{}gs;
s{^\s*|\s*|<[^>]*>}{}gs;
return $_ unless /^$|Queuing|Compiling|Running/;
sleep $interval;
}
}
要完成提交操作需要提供cookie,通常有两种办法,一是直接在WebClient.Headers里设置好cookie,以前我用C#写的一个ZOJ的自动提交机就是这么实现的;更简单的办法是给UserAgent初始化一个空的cookie,通过完成login来设置cookie。有了cookie后就可以submit了,submit需要提供problemid, language和usercode。submit后可以通过laststatus来获得你最近一次提交的返回结果。先用A + B Problem来测试一下模块,这里用了caller函数,实现模块的测试和使用两不误。
# HDOJAgent.pm
return 1 if caller;
my $hdoj = new HDOJAgent('wabots');
$hdoj->login('~!@#$%^&*()_+');
$hdoj->problemid(1000); # A + B Problem
$hdoj->language(1); # GCC
$hdoj->submit(<<GCC
main(a,b){while(scanf("%d%d",&a,&b)>0)printf("%d\n",a+b);}
GCC
);
print $hdoj->laststatus, "\n";
Generated feed for “http://www.zju.edu.cn/”
from http://www.zju.edu.cn/ Google feed by Google
* Google was not able to access this page to check for updates. This page may be unavailable or have other restrictions that prevent Google from getting updates.
于是自己写了一个简单的脚本,自己为这些页面生成一个RSS。
#!/usr/bin/perl
# wafeed.pl
use AnyDBM_File;
use DBM_Filter;
use Encode qw(decode_utf8);
use LWP::Simple qw(get);
use XML::FeedPP;
$config = $ARGV[0] || 'config.pl';
require $config;
$time = time;
if (-e $rssfile) {
$feed = new XML::FeedPP::RSS($rssfile, utf8_flag => 1);
} else {
$feed = new XML::FeedPP::RSS;
}
$feed->title($title);
$feed->link($link);
$feed->pubDate($time);
$feed->description($description);
dbmopen(%history, $dmbfile, 0666);
(tied %history)->Filter_Push('utf8');
while (($key, $cfg) = each %config) {
$value = get($cfg->{'link'});
$value = $cfg->{'handler'}($value) if defined $cfg->{'hand'};
$value = decode_utf8($value);
if ($value !~ /^\s*$/ && $value ne $history{$key}) {
$history{$key} = $value;
$feed->add_item(
title => $cfg->{'title'},
link => $cfg->{'link'},
pubDate => $time,
description => $value);
}
}
dbmclose %history;
$feed->sort_item();
$feed->limit_item($itemnum);
$feed->to_file($rssfile);
This is a “postponed” regular subexpression. The “code” is evaluated at run time, at the moment this subexpression may match. The result of evaluation is considered as a regular expression and matched as if it were inserted instead of this construct.