继续上篇文章,紧天吃午饭的时候觉得那里说的两种方向都不太容易解决。Python的那个最诡异,实在不知道是哪里的问题,而且Python那个脚本,用了几个库,好像我目前手上能用的虚拟主机上(Dreamhost和SDF)都没有;Bash的那个,我实在是不想把目前的宝贵时间花在学习一门新语言上。然后就想到了我过去最喜欢的Perl,既然它被称为是一门“粘合语言”,应该在里面可以直接调用yegle写的wget语句,而且前两天用Perl写过海词客户端简化版,里面就用了正则表达式来处理了HTML。相对与海词的那个排版混乱的HTML输出,Twitter给的XML可简单清晰多了。
我不知道Perl里怎么解析XML,不过Twitter的XML很简单,我几下就弄出了需要的最新的tweet文本和那一条tweet的时间。然后用yegle的wget语句提交,一下子就成功了。然后就发现了一个困扰了我长时间的问题:如果tweet里面是中文,就无法提交(实际上是提交了一个空信息)。然后让程序打印初那条tweet的文字,发现都成了写;这样的东西,然后就到处研究怎么把它转换成正常的文字。后来从这里知道了需要用HTML::Entities来处理(代码里第38行)。做了这一步后那些wget语句就又好使了。
结下来就是隔一段时间就运行一下这个程序了。cron似乎是我第一个想到的。还有一个方法就是在Perl脚本里用循环,不过这样似乎有点不妥(具体怎么不妥我没有自习琢磨)。我的MacBook虽然基本上保持开机状态,不过把它放在24小时运行的网上的虚拟主机上似乎更不错。我目前有两个虚拟主机帐号,一个是Dreamhost,一个是SDF。结果两个都有问题:Dreamhost上的wget版本太老,不支持命令行里的那些session、cookies功能;SDF则不让我用cron。SDF的问题不大好办,似乎cron是它们专门的用户帐号才能做的,我目前的ARPA帐号不在此范围。我只好试着下载wget的代码在Dreamhost上编译。结果出乎我意料,居然编译成功了!我过去在不是本地的主机上编译软件通常是以失败而告终的。用了新版本的wget,程序就运行正常了。设定好了cron(我让程序2分钟运行一次,查看了Dreamhost的wiki上关于cron的说明,没有提到有什么限制),程序运行OK。
这时还有最后一个问题没解决:如果让这段代码隔一段时间就自动运行,那么如果在这段时间里面没有更新Twitter,那么校内的状态会被不断用同一条tweet刷新。这也是我要保存最新tweet的发布时间的目的。我用的方法是把这一条tweet的发布时间写到一个磁盘文件中去,然后下一次运行的时候比较两个时间,如果两个时间不同,就运行发布的wget命令,然后更新磁盘文件,否则就退出程序。我不知道有没有更好的解决方案,不过我的方法目前还可行。
最后就是把代码贴出来了。我整理了一下,把用户名、帐号、磁盘文件、还有wget程序的地址都弄成了变量,放在代码最前面以方便设定。完事后看起来还不错。
!/usr/bin/perl -w
Twitter -> Xiaonei status sync tool.
Author: Feng Liu me@liuf.net
Version: 1.0
Date: Tue Apr 21 23:06:40 +0000 2009
use utf8;
use Encode;
use LWP::Simple;
use HTML::Entities;
####################### Settings starts here #######################
Set your base account information here. Don't show this to others!
my $twitter_account = '';
my $xiaonei_email = '';
my $xiaonei_passwd = '';
some machine's wget is too old, so you may need to rebuild a newer
version and indicate the path of your own wget here.
my $wget_cmd = 'wget';
The program needs a log file for keeping the time of your last
tweet. Otherwise you may get your xiaonei status updated to a same
tweet. So please keep this file!
my $logfile = '/tmp/twxn.log';
######################## Settings ends here ########################
my $twitter_url = 'http://twitter.com/statuses/user_timeline/' . $twitter_account . '.xml';
my $statuses = get($twitter_url);
my @lines = split /\n/, $statuses;
my $latest_text = $lines[5];
my $latest_time = $lines[3];
if ($latest_text =~ /
$status = $1;
};
$text = decode_entities($status);
If the log file doesn't exist, create a new one.
if (!(-e $logfile)) {
open LOG,"> /tmp/twxn.log" or die "ERROR: Cannot create log file.";
close LOG;
print "Created a new log file: $logfile\n";
}
open LOG, "< $logfile" || die "ERROR: Cannot open log file!";
$last_time =
close LOG;
if ($last_time ne $latest_time) {
my $login_cmd = $wget_cmd . ' --no-proxy -O xiaoneilogin.log --post-data="email=' . $xiaonei_email . '&password=' . $xiaonei_passwd . '&autoLogin=true" --keep-session-cookies --save-cookies=xiaoneicookie http://login.xiaonei.com/Login.do';
my $post_cmd = $wget_cmd . ' --no-proxy -O xiaoneipost.log --post-data="c=' . $text . '" --keep-session-cookies --load-cookies=xiaoneicookie http://status.xiaonei.com/doing/update.do --referer=http://status.xiaonei.com/getdoing.do';
system($login_cmd);
system($post_cmd);
open LOG, "> $logfile" || die "ERROR: Cannot open log file!";
print LOG $latest_time;
close LOG;
}