当前位置:首页 >> 脚本专栏

使用Ruby来编写访问Twitter的命令行应用程序的教程

简介

Twitter 现已成为社交网络中的佼佼者。Twitter 只允许用户发布不多于 140 个字符的内容,谁能够想到,这个过去毫不起眼的小网站如今却价值十多亿美元,拥有数百万用户,Twitter 平台上已构建了大量的应用程序,并且不断有新的开发人员准备投入这一浪潮中。

本文并不打算介绍 Twitter(事实上,也没有这个必要)。相反,本文将介绍如何访问 Twitter 平台来构建出色的命令行应用程序。Twitter 支持各种编程语言,包括 C++、Java"htmlcode">

require 'rubygems'
require 'twitter'

第一个 Twitter 脚本

现在,您已经准备好构建第一个应用程序,该应用程序用于检测您所关注的人的位置。首先创建一个脚本,它会获取其他人的姓名,并告诉您他们的当前位置。清单 1 显示了相关代码。
清单 1. 跟踪用户位置

require 'rubygems'
require 'twitter'

def track
 ARGV.each do |name|
  puts name + " => " + Twitter.user("#{name}").location
 end
end

track

这段代码执行了哪些操作?如果您刚刚接触 Ruby,则需要向您解释一下,ARGV 是一个数组,它提供脚本对命令行参数的访问。Twitter.user API 返回有关您对其位置感兴趣的人的信息。调用以下脚本可以获得 Lady Gaga、Ashton Kutcher 和 Oprah Winfrey 的当前位置:

bash$ ./location_tracker.rb ladygaga aplusk Oprah
ladygaga => New York, NY
aplusk => Los Angeles, California
Oprah => Chicago, IL

在 Twitter 上实现用户搜索并了解认证情况

现在,让我们搜索 Twitter 上的一些现有用户。如果可以猜出用户的 Twitter ID,那么可以使用以下命令行:

require 'rubygems'
require 'twitter'
puts "User exists" if Twitter.user"htmlcode">
require 'rubygems'
require 'twitter'
names = Twitter.user_search("Arpan")

但是这段代码未能正常工作。清单 2 显示的错误日志告诉您问题出现在哪里。
清单 2. 无法执行用户搜索

Twitter::Unauthorized: GET https://api.twitter.com/1/users/search.json"htmlcode">
Twitter.configure do |config|
 config.consumer_key = "mT4atgBEKvNrrpV8GQKYnQ"
 config.consumer_secret = "BiQX47FXa938sySCLMxQCTHiTHjuTTRDT3v6HJD6s"
 config.oauth_token = "22652054-Yj6O38BSwhwTx9jnsPafhSzGhXvcvNQ"
 config.oauth_token_secret = "o9JuQuGxEVF3QDzMGPUQS0gmZNRECFGq12jKs"
end

注意,清单 3 中的条目是虚构的:您需要在脚本中填充自己的内容。顺利完成认证后,就可以搜索名为 Arpan 的人(参见下面的 清单 4)。
清单 4. 在 Twitter 上搜索用户

require 'rubygems'
require 'Twitter'

Twitter.configure do |config|
 config.consumer_key = "mT4atgBEKvNrrpV8GQKYnQ"
 config.consumer_secret = "BiQX47FXa938sySCLMxQCTHiTHjuTTRDT3v6HJD6s"
 config.oauth_token = "22652054-Yj6O38BSwhwTx9jnsPafhSzGhXvcvNQ"
 config.oauth_token_secret = "o9JuQuGxEVF3QDzMGPUQS0gmZNRECFGq12jKs"
end

users = Twitter.user_search(ARGV[0])
users.each do |user|
 print "\n" + user.name + " => " 
 print user.location unless user.location.nil"htmlcode">
Arpan Jhaveri => New York
Arpan Boddishv =>
Arpan Peter => Bangalore,India
Arpan Podduturi => NYC
Arpan Kumar De => IIT Kharagpur
Arpan Shrestha => Kathmandu, Nepal
Arpan Divanjee => Mumbai,India
Arpan Bajaj => Bay Area, CA

您可能期望获得更多结果。Arpan 这个名字(印度姓名)并不少见,那么为什么搜索结果这么少?最后您会发现,user_search 使用了一个可选参数(一个 Ruby hash 表),您也可以指定可产生更多结果的选项。因此,可以稍微修改一下清单 5 的代码,传递可选的 hash 参数(#)并预填充它的值。例如,如果希望在一个页面中填充 15 项结果,那么可以使用 清单 6 中的代码。
清单 6. 在每个页面显示 15 项搜索条目

require 'rubygems'
require 'twitter'

#.. authentication code here
users = Twitter.user_search(ARGV[0], {:per_page => 15})
#... same as Listing 10

是不是可以在每个页面中显示 100 项条目?不行,Twitter.user_search 允许每页显示的最多条目为 20。清单 7 显示了如何在每个页面中显示 20 个条目。
清单 7. 每个页面显示 20 个条目

#... usual authentication stuff

pagecount = 0
while pagecount < 10
 u = Twitter.user_search("#{ARGV[0]}", {:per_page => 20, :page => pagecount})
 u.each do |user| 
 print "\n" + user.name + " => " + user.screen_name
 print " => " + user.location unless user.location.nil"htmlcode">
#... user authentication 
pagecount = 0
while pagecount < 10
 u = Twitter.user_search("#{ARGV[0]}", {:per_page => 20, :page => pagecount})
 u.each do |w| 
 if w.location == "New York"
  results = Twitter::Search.new.from(w.screen_name).containing("ruby").fetch
  puts w.screen_name if results.size > 10
 end
 end unless u.size < 20
 pagecount += 1
end

这里发生了什么呢?代码首先使用 Twitter::Search.new 创建了一个搜索客户端。接下来,要求搜索客户端从包含 ruby 的相应用户那里获取所有 tweet。最后,代码返回一组结果,如果在 tweet 中提到 Ruby 的次数超过十次,则将此人定义为喜欢 Ruby 的人。

让我们尝试为 hash 标记 #ruby 获取一组 tweet。下面是具体实现:

#... user authentication code
results = search.hashtag("ruby").fetch
results.each do |r|
 puts r.text + " from " + r.from_user
end

不过,还可以实现更多内容。对于 ruby 之类的 hash 标记,您希望获得数百个条目,不是吗?对于这种情况,使用搜索客户端也会带来便利,因为您可以从搜索客户端轻松地检索下一个页面。清单 9 的代码显示了有关 Ruby 的十页 tweet。
清单 9. 显示多个页面

更多搜索选项

搜索客户端可以让您实现更出色的功能,比如使用特定语言或来自某个地方(比如德国)的 tweet。您甚至可以搜索提到特定用户的 tweet,或搜索匹配特定条件的 tweet。例如,搜索所有提到 Ruby 但没有提到 Rails 的 tweet?尝试下面的代码:

search.containing("ruby").not_containing("rails").fetch

当然,您可以像下面这样进行串联:

search.containing("ruby").not_containing("rails").mentioning("username").from("place-id")

搜索短语非常直观。例如,输入以下代码:

search.phrase("ruby on rails").fetch

现在,您已经掌握了入门要领!
速度限制

关于 Twitter,您需要了解一件重要的事情,即速度限制,Twitter 非常重视这个问题。速度限制意味着 Twitter 只允许您的脚本每个小时执行有限次数的查询。您可能已经发现,对于某些应用程序,您不需要进行显式的认证,但是对于另外一些应用程序,认证则是必须的。对于不包含 OAuth 标记的应用程序,当前的最大限制是每小时执行 150 个调用;对于带有该标记的应用程序,允许每小时执行 350 个调用。有关 Twitter 速率限制的最新信息,请查看 参考资源。要了解您的脚本认证的当前限制,请添加以下代码:

puts Twitter.rate_limit_status

下面是输出结果:

<#Hashie::Mash hourly_limit=350 remaining_hits=350 reset_time="Sat Aug 13 21:48:
59 +0000 2011" reset_time_in_seconds=1313272139>

如果您希望获得更具体的结果,请用代码查看下面的内容:

Twitter.rate_limit.status.remaining_hits

下面的输出禁用了认证。注意,您已经用完了可用限制的 50%:

<#Hashie::Mash hourly_limit=150 remaining_hits=77 reset_time="Sat Aug 13 21:13:5
0 +0000 2011" reset_time_in_seconds=1313270030>

更新 Twitter 的状态,重新发布 tweet 和其他内容

搜索功能暂时告一段落。现在需要使用脚本更新 tweet 的状态。只需一行代码即可(当然,您需要在脚本中包含认证代码):

#... authentication code
Twitter.update (ARGV [0])

将代码保存为 update.rb,并以 ruby update.rb "Hello World from Ruby Script" 的形式从命令行调用它。现在,您的 Twitter 页面已经实现了更新!对话功能是 Twitter 的一个自然扩展,向另一个用户发送消息非常简单:

#... authentication code
Twitter.direct_message_create("username", "Hi")

您可以选择使用用户的屏幕名或数字 ID 发送消息。Twitter 的另一个有趣特性是可以快速查看最近发送的和最近接收到的 20 条消息:

#... authentication code
Twitter.direct_messages_sent.each do | s | 
 puts "Sent to: " + s.recipient_screen_name
 puts "Text: " + s.text
end

我们有时候需要强调某些 tweet 的重要性,一个好方法就是重新发布 tweet。下面显示了重新发布的最近 20 个 tweet:

#... authentication code
Twitter.retweets_of_me.each do |rt|
 print rt.text
 puts " retweet count = " + rt.retweet_count.to_s
end

当然,如果能知道是谁在重新发布 tweet 就更好了,但是无法从 retweets_of_me API 直接获取该信息。相反,您需要使用 retweeters_of API。注意,每个 tweet 都有一个唯一的 ID,而 retweeters_of 需要获得这一 ID。清单 10 展示了相关代码:
清单 10. 谁在向我重新发布 tweet

#... authentication code
Twitter.retweets_of_me.each do |rt|
 print rt.text
 print " retweeted by " 
 Twitter.retweeters_of(rt.id).each do |user|
 puts user.screen_name
 end
end

用 Twitter 实现有趣的功能

您可以利用自己的脚本做许多有趣的事情。例如,假如您很关心当前 Twitter 中正在发生的事情,那么您可以获取前十个趋势:

Twitter.trends.each do | trend | 
 puts trend.name
end

twitter.com 只能报告前十个趋势。参考 参考资源,获得有关的更多信息。通常,您可能只关心所在地的趋势。只需要提供所在地的 where-on-earth ID (WOEID),Twitter 就可以提供这些信息。下面我展示了如何获得印度的当前趋势:

Twitter.local_trends(12586534 ).each do | trend | 
 puts trend #local_trends returns String
end

获得 Twitter 推荐的用户也很容易。首先查看以下脚本:

Twitter.suggestions("technology").users.each do | user | 
 puts user.screen_name
end

我对这段代码的输出进行了仔细检查。前十个结果意味着这段代码可以正常工作。Twitter 提供了不同的用户感兴趣的类别,通过调用 Twitter.suggestions(只需将 Twitter.suggestions 放在脚本里)便可获得此信息。每个类别都有一个简短名称,在 Twitter 中称为 slug,您需要将其传递给 Twitter.suggestions,然后便可获得 Twitter 推荐的用户。清单 11 展示了相关输出。
清单 11. 技术类别中推荐的前几名用户

gruber
dannysullivan
AlecJRoss
timoreilly
Padmasree
tedtalks
OpenGov
twitter
BBCClick
woot
anildash
laughingsquid
digiphile
jennydeluxe
biz
ForbesTech
chadfowler
leolaporte

本文最后将介绍如何找到 Sachin Tendulkar(最棒的板球队员)的最受欢迎的粉丝。首先,Sachin 的 ID 是 sachin_rt(在相关主题上,您可以使用 Twitter.user("sachin_rt").follower_count 查看其粉丝的数量,并使用 Twitter.user("sachin_rt").verified 确认他的状态)。

现在,使用 Twitter.follower_ids("sachin_rt") 获得 Sachin 粉丝的数量。默认情况下,您将获得 5000 名用户,这足够支持您完成下面的工作。确保您已经阅读 Twitter 文档并参考了 Twitter 的 API resources for friends and followers,了解如何获得完整的粉丝列表。下面是一个代码示例:

#... authenticate yourself
puts Twitter.follower_ids("sachin_rt").ids.size

最后,根据 follower_count 对这 5000 名用户中的某些用户进行排序:

#... authenticate yourself
puts Twitter.follower_ids("sachin_rt").ids[0..49].sort!{|a, b| \ 
 Twitter.user(a).followers_count <=>  Twitter.user(b).followers_count}.reverse.first.name

在 sort 之后,"!" 表示排序对所调用的内容修改了数组(并且没有返回新的数组),花括号({})中的代码是比较功能。这解释了使用 Ruby 的另一个原因:能够在一行代码中实现 20 行 C++ 代码完成的工作。

结束语

为 Twitter 编写命令行脚本非常有趣,并且可以使您洞悉 Twitter 尚未提供的功能。此外,无论是搜索符合您的条件的特定用户(从本地技术人员到领域中的主题专家),还是搜索令人兴奋的新 tweet,都可以很方便地通过命令行来实现。在结束本文之前,我需要给出最后两条忠告:首先,Twitter 非常在意每小时的速率限制,因此最好将搜索结果缓存到您的代码中。其次,随时关注 Twitter 的 REST API 资源,其中列出了您的 Twitter 客户端的所有 API。最重要的是,尽情享受 Twitter 的乐趣!