使用Perl构建Twitter机器人

继上周关于使用Perl构建Reddit机器人的文章之后,让我们看看如何使用Perl构建一个Twitter机器人。正如你所预期的,Perl使这变得容易,但在我们进入代码之前,让我们谈谈优点。
将推文自动化添加到现有应用程序中可以带来许多好处。首先,它可以节省时间,让你专注于其他更有价值的活动。自动化可以保护你免受手动转录错误(如拼写错误和损坏的URL)的影响。自动化还意味着增加推文数量更便宜,在其他条件相同的情况下,更高的推文数量将导致更多的Twitter粉丝。听起来不错?太好了,那么让我们来看看代码吧!
编写推文
编写推文的核心代码非常简单。我正在使用Net::Twitter::Lite发行版,它支持Twitter的最新版本API。
use strict;
use warnings;
use Net::Twitter::Lite::WithAPIv1_1;
sub tweet
{
my ($text) = @_;
my $twitter = Net::Twitter::Lite::WithAPIv1_1->new(
access_token_secret => $ENV{TWITTER_ACCESS_SECRET},
consumer_secret => $ENV{TWITTER_CONSUMER_SECRET},
access_token => $ENV{TWITTER_ACCESS_TOKEN},
consumer_key => $ENV{TWITTER_CONSUMER_KEY},
user_agent => 'TwitterBotExample',
ssl => 1,
);
$twitter->update($text);
}
代码导入Net::Twitter::Lite::WithAPIv1_1
以使用新的Twitter API。子程序tweet
接受一些文本作为参数。然后它创建一个新的Net::Twitter::Lite::WithAPIv1_1
对象,使用环境变量作为凭证。如果你还没有这些凭证,你可以免费注册你自己的Twitter账户并生成令牌。最后,子程序调用update
方法来推文。
现在我可以通过在代码中添加这一行来发送一条推文
tweet("This is a computer speaking!");
安全第一
到目前为止一切顺利,但是这段代码并不安全。如果未提供$text
作为参数,或者我们的环境变量未声明,或者调用Twitter失败,会发生什么?我将添加一些检查来处理这些场景。
use strict;
use warnings;
use Net::Twitter::Lite::WithAPIv1_1;
use Try::Tiny;
sub tweet
{
my ($text) = @_;
die 'tweet requires text as an argument' unless $text;
unless ($ENV{TWITTER_CONSUMER_KEY}
&& $ENV{TWITTER_CONSUMER_SECRET}
&& $ENV{TWITTER_ACCESS_TOKEN}
&& $ENV{TWITTER_ACCESS_SECRET})
{
die 'Required Twitter Env vars are not all defined';
}
try
{
my $twitter = Net::Twitter::Lite::WithAPIv1_1->new(
access_token_secret => $ENV{TWITTER_ACCESS_SECRET},
consumer_secret => $ENV{TWITTER_CONSUMER_SECRET},
access_token => $ENV{TWITTER_ACCESS_TOKEN},
consumer_key => $ENV{TWITTER_CONSUMER_KEY},
user_agent => 'TwitterBotExample',
ssl => 1,
);
$twitter->update($text);
}
catch
{
die join(' ', "Error tweeting $text",
$_->code, $_->message, $_->error);
};
}
这段代码与之前大致相同,但现在它会在处理之前检查所需变量。代码还导入了Try::Tiny,因为我已经在Twitter代码周围添加了try/catch块。如果在Twitter交互中抛出异常,则激活catch块。由于Net::Twitter::Lite抛出结构化异常,catch块通过从结构化异常中提取信息来构建异常字符串,然后自己调用die
。
你可能想知道是否真的需要调用die
。我们能否只是返回undef
而不是退出程序?调用die
的优点是,tweet
子程序的调用者可以更好地决定如何处理该问题,因此我们将该决定推迟给他们。如果调用代码没有正确处理die
,我们知道程序将退出。但如果我们返回undef
,我们就不会有这样的保证。但这并不意味着代码必须退出。让我们假设我有一百多条推文要发送,也许我只是想将错误记录在某个地方并继续进行。
foreach my $text (@tweet_texts)
{
try
{
tweet($text);
}
catch
{
log_error($_);
};
}
如果我正在打印一系列推文,其中顺序很重要,我仍然可以记录错误,但然后调用die
来退出程序。
foreach my $text (@sequence_of_texts)
{
try
{
tweet($text);
}
catch
{
log_error($_);
die $_; # exit the program
};
}
更好的文本处理
现在代码更安全了,我们还能如何改进它?一个著名的限制是推文长度不能超过140个字符。现在,如果tweet()
子程序收到了一个超过140个字符的文本字符串,Twitter API将拒绝它,引发异常,然后代码将退出。我认为我们可以做得更好。
当我思考我发送的推文内容时,我通常会在推文中分享关于Perl的文章链接。这些链接通常包括一些文本、一个URL和一个话题标签。将它们分别传递给tweet()
函数是很有用的,因为为了使所有内容都适应,你可能需要截断文本,但你不想截断URL或话题标签,因为这样可能会改变其意义,或者破坏URL。
use strict;
use warnings;
use Net::Twitter::Lite::WithAPIv1_1;
use Try::Tiny;
sub tweet
{
my ($text, $url, $hashtag) = @_;
unless ($text && $url && $hashtag)
{
die 'tweet requires text, url and hashtag arguments';
}
unless ($ENV{TWITTER_CONSUMER_KEY}
&& $ENV{TWITTER_CONSUMER_SECRET}
&& $ENV{TWITTER_ACCESS_TOKEN}
&& $ENV{TWITTER_ACCESS_SECRET})
{
die 'Required Twitter Env vars are not all defined';
}
# build tweet, max 140 chars
my $tweet;
if (length("$text $hashtag") < 118)
{
$tweet = "$text $url $hashtag";
}
elsif (length($text) < 118)
{
$tweet = "$text $url";
}
else # shorten text, drop the hashtag
{
$tweet = substr($text, 0, 113) . "... " . $url;
}
try
{
my $twitter = Net::Twitter::Lite::WithAPIv1_1->new(
access_token_secret => $ENV{TWITTER_ACCESS_SECRET},
consumer_secret => $ENV{TWITTER_CONSUMER_SECRET},
access_token => $ENV{TWITTER_ACCESS_TOKEN},
consumer_key => $ENV{TWITTER_CONSUMER_KEY},
user_agent => 'TwitterBotExample',
ssl => 1,
);
$twitter->update($tweet);
}
catch
{
die join(' ', "Error tweeting $text $url $hashtag",
$_->code, $_->message, $_->error);
};
}
Twitter将URL视为长度为12个字符。现在代码会检查我们参数的长度,如果需要,会截断$text
。只有当有足够的空间时,话题标签才会被包含。
这段代码对我来说是有效的,但你可能想要做一些不同的处理。Twitter凭据可以存储在一个配置文件中,而不是环境变量中。$hashtag
参数可以是一个包含话题标签的数组引用,这些标签可以逐步添加到推文文本中,而不是一个单一的文本字符串,这样可以避免全部或无的取舍。
这篇文章最初发布在PerlTricks.com上。
标签
反馈
这篇文章有什么问题吗?请帮助我们通过在GitHub上打开一个问题或拉取请求来解决。