Accessing Twitter from the command line

Using the Twitter platform to build cool command-line apps

As a social networking medium, Twitter is a lot of fun. But with a bit of command-line savvy, the right API, and your programming language of choice, it can also be powerful. Learn how to access the Twitter platform to build useful and fun command-line applications.

Share:

Arpan Sen (arpansen@gmail.com), Independent author

Arpan Sen is a lead engineer working on the development of software in the electronic design automation industry. He has worked on several flavors of UNIX, including Solaris, SunOS, HP-UX, and IRIX as well as Linux and Microsoft Windows for several years. He takes a keen interest in software performance-optimization techniques, graph theory, and parallel computing. Arpan holds a post-graduate degree in software systems. You can reach him at arpansen@gmail.com.


developerWorks Contributing author
        level

08 November 2011

Also available in Chinese Russian

Introduction

Twitter is a phenomenon in the social networking space. Who would have guessed that the once-obscure site that allowed users to communicate in 140 characters or less would end up with a billion-dollar plus valuation, millions of users, hoards of applications built on top of the Twitter platform, and newer developers ever ready to jump on the bandwagon?

This article is no introduction to Twitter (it really needs none, anyway). Instead, it shows you how to access the Twitter platform to build cool command-line applications that are fun. Twitter is available for access from a whole host of programming languages, including C++, Java™, Perl, Ruby, PHP, and Python. Within each language, there is a choice of libraries or packages that do a lot of the hard work for you. So let's get started.

This article starts out using Ruby with Twitter. You should have at lease a passing familiarity with Ruby, but even without that, it's easy enough to pick Ruby up on the go.


Installing the Twitter gem

Several gems are available for accessing Twitter from Ruby (see Resources for links to more information). For this article, I opted for twitter, a Ruby wrapper by John Nunemaker. Installing the gem is a breeze:

bash$ gem install twitter

This command installs the Twitter client on your machine. If you have a custom gem installation folder, then you first need to invoke rubygems and then twitter from your script. Here's how:

require 'rubygems'
require 'twitter'

Your very first Twitter script

That's it. Now, you're ready to build your first application, which is designed to spy on the location of your favorite people. Start by creating a script that takes in the name of the people and tells you their current location. Listing 1 below shows the code.

Listing 1. Tracking user location
require 'rubygems'
require 'twitter'

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

track

So, what's happening here? If you're new to Ruby, ARGV is the array that gives the script access to command-line parameters. The Twitter.user API returns a whole host of information of which you're really only interested in the location for now. Invoking the script to figure out the current location of Lady Gaga, Ashton Kutcher, and Oprah Winfrey tells you what you knew anyway:

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

Now, let's search for some specific user already in Twitter. If you can guess the user's Twitter ID, you can use the following command line:

require 'rubygems'
require 'twitter'
puts "User exists" if Twitter.user?(ARGV[0])

More often than not, however, you won't be able to guess the ID. So, something like searching for user names would be required. That brings us to the following bit of code, which searches all users whose name matches Arpan:

require 'rubygems'
require 'twitter'
names = Twitter.user_search("Arpan")

But this code won't work. The error log shown in Listing 2 should tell you what the problem is.

Listing 2. Oops, could not perform user search
Twitter::Unauthorized: GET https://api.twitter.com/1/users/search.json?q=Arpan%
20Sen: 401: Could not authenticate you.
        from D:/Ruby/lib/ruby/gems/1.8/gems/twitter-1.6.2/lib/faraday/response/r
aise_http_4xx.rb:12:in `on_complete'
        from D:/Ruby/lib/ruby/gems/1.8/gems/faraday-0.7.4/lib/faraday/response.r
b:9:in `call'
        from D:/Ruby/lib/ruby/gems/1.8/gems/faraday-0.7.4/lib/faraday/response.r
b:62:in `on_complete'

From this code, it's clear that you first need to authenticate yourself with Twitter before you can do anything else. This is not going to be your login/password combination; it's your script (called an app in Twitter terminology) that needs authentication, not you. Keeping this difference in mind, go to http://dev.twitter.com/apps and log in with your usual login and password. Twitter will ask for an app name, a description, and a placeholder website for your app. After you provide this information, you should have the four entries that help the script authenticate:

  • Consumer key
  • Consumer secret token
  • Consumer OAuth key
  • Consumer OAuth secret token

Now, inside the Ruby code, you need to populate the Twitter.configure object with these options. Listing 3 below shows the code.

Listing 3. Configuring your script for authentication
Twitter.configure do |config|
  config.consumer_key = "mT4atgBEKvNrrpV8GQKYnQ"
  config.consumer_secret = "BiQX47FXa938sySCLMxQCTHiTHjuTTRDT3v6HJD6s"
  config.oauth_token = "22652054-Yj6O38BSwhwTx9jnsPafhSzGhXvcvNQ"
  config.oauth_token_secret = "o9JuQuGxEVF3QDzMGPUQS0gmZNRECFGq12jKs"
end

Note that the entries in Listing 3 are just dummy entries; you need to populate your own in the script. With authentication out of the way, you can search for people named Arpan (see Listing 4 below).

Listing 4. Searching for people on 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?
end

Now, when you save your script as search_for.rb and invoke the same on the command line as ./search_for.rb Arpan, you would get the names shown in Listing 5.

Listing 5. Output from the code in Listing 4
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

You were probably expecting a few more results. The name Arpan (which is an Indian name) is not terribly uncommon, so what's happening? It turns out that user_search takes an optional argument (a Ruby hash table), and you could also specify options that would produce more results. So, modify the code in Listing 5 slightly to pass the optional hash argument (#) and have its values pre-populated. For example, if you want to have a single page filled with 15 entries, you would use the code in Listing 6.

Listing 6. Displaying 15 search entries per page
require 'rubygems'
require 'twitter'

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

Does this mean you can have 100 entries on a page? No, Twitter.user_search restricts the maximum number of entries per page to 20. Listing 7 shows the code that would get you 10 pages of 20 entries each.

Listing 7. Displaying 20 entries per page
#... 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?
  end unless u.size < 20
  pagecount += 1
end

Much better. Now that you have the users by your preferred name and their screen names, let's move on to more interesting things. How about searching for people named Nick who stay in New York and love Ruby? You can get the name and location bit from user_search, but what about Ruby? That brings us to the next thing to learn: Creating custom search clients.

Using the Twitter::Search class

You use the Twitter::Search class to create custom search clients. Listing 8 below shows the code.

Listing 8. Learning to use the Twitter::Search class
#... 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

What's happening here? The code begins by creating a search client using Twitter::Search.new. Next, you ask the search client to get all the tweets from the corresponding user that contains ruby. Finally, the code fetch returns an array of the results, and you decide that mentioning Ruby more than 10 times in your tweets is the way to show you love your language.

Let's try to get an array of tweets for the hash tag #ruby. Here's how:

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

Okay, there's more to it. For a hash tag like ruby, you expect hundreds of entries, right? This is also where using the search client comes in handy, because you can easily retrieve the next page from the search client. The code in Listing 9 below retrieves 10 pages of tweets on Ruby.

Listing 9. Displaying multiple pages with search
#... user authentication code
results = search.hashtag("ruby").fetch
count = 0

while count < 10 
  results.each do |r|
    puts r.text + " from " + r.from_user
  end
  results = search.fetch_next_page
  count += 1
end

The search client lets you do more cool things, like searching for tweets that are only in a specific language or originate from, say, Germany. You can even search for tweets that mention specific users or searches that match specific conditions. For example, care to search all tweets that mention Ruby but not Rails? Try this code:

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

You can, of course, keep on cascading like thus:

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

Searching for phrases is intuitive. For example, type the following code:

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

Now, you are good to start!

Rate limiting

While we're are at this game, here's an important piece of information that you need to digest. It's called rate limiting, and Twitter is pretty serious about it. Rate limiting means that Twitter lets your script make only a limited number of queries every hour. As you have already seen, for some types of apps you do not need explicit authentication, while for others you do. For apps without the OAuth token, 150 calls per hour is the current maximum; for those with the token, 350 per hour are allowed. For the latest information about Twitter policies on rate limiting, check out Resources. To know your current limit in your script with the authentication section, add the following line:

puts Twitter.rate_limit_status

Here's the output:

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

If you want to be more specific, check for the following in your code:

Twitter.rate_limit.status.remaining_hits

Incidentally, here is the output with authentication turned off. Note that you have used up 50 percent of the available limit:

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

Updating Twitter status, retweets, and more

Enough of searching for a while. Now you need to update your Twitter status using the script. Just a one liner—that's all there is to it (of course, you do need to have the authentication code in the script):

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

Save this code as update.rb and invoke it from the command line as ruby update.rb "Hello World from Ruby Script". Magically, the update is now on your Twitter page! Conversations are but a natural extension of Twitter, and it's easy to send a direct message to another user:

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

Here, you have the option of sending a message either by using the user's screen name or the numeric ID. Another interesting feature available with Twitter is that the 20 most recent messages sent by me and to me are available for a quick reference:

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

We all want to feel important at times, and what better way than to check for other users retweeting your tweets. Here are the 20 most recent tweets being retweeted:

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

Of course, it would be cool to know who is retweeting, but there's no direct way to get that information from the retweets_of_me API. Instead, you need to use the retweeters_of API. Note that each tweet has a unique ID, and retweeters_of needs to be passed that same ID. Listing 10 below shows the code:

Listing 10. Who's retweeting me
#... 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

Fun things to do with Twitter

You can do a whole host of other things with your script. For example, say you're curious to know what's currently going on in the Twitter world. You can retrieve the top 10 trends:

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

Incidentally, twitter.com restricts itself to report only 10 items for top trends. Refer to Resources for details. And typically, you're only interested in trends that concern your local area. Twitter can provide you with that information subject to you providing the where-on-earth ID (WOEID) and that local area having topics trending. Here's how I get what's trending for India:

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

Getting the top Twitter suggested users is easy, too. Check out the script first:

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

I double-checked the output I got from this code. The fact that timoreilly made the top 10 meant that the code's working just fine. Twitter has several categories of user interest that you can get to readily by making a call to Twitter.suggestions (you just put Twitter.suggestions in the script). Each category has a short name, called slug in Twitter terminology, that you need to pass to Twitter.suggestions to get a list of the top suggested users. Listing 11 below shows the output.

Listing 11. Top suggested users in the technology category
gruber
dannysullivan
AlecJRoss
timoreilly
Padmasree
tedtalks
OpenGov
twitter
BBCClick
woot
anildash
laughingsquid
digiphile
jennydeluxe
biz
ForbesTech
chadfowler
leolaporte

This article ends by figuring out some of Sachin Tendulkar's (arguably the best cricketer ever) more popular followers. To start, Sachin's ID is sachin_rt (on a related topic, you can check his follower count with Twitter.user("sachin_rt").follower_count and confirm his verified status with Twitter.user("sachin_rt").verified)).

Now, use Twitter.follower_ids("sachin_rt") to get the number of Sachin's followers. By default, you would get 5000 users, and that's enough to get you going. Be sure to read the Twitter documentation and refer to Twitter's API resources for friends and followers for details on how to get the entire follower list. Here is the code example:

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

Finally, let's just sort some 50 of these 5000 users based on their follower_count:

#... 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

The "!" after sort indicates that the sort is modifying the same array on which it was invoked (and not returning a new one), and the code within the curly brackets ({}) is the comparison function. This highlights another reason to use Ruby: What would have taken 20 lines of C++ code gets done in a single line of code here.


Conclusion

Doing command-line scripting for Twitter is fun and gives you insights that are not readily available (yet) from Twitter. What's more, searching for specific individuals who fit your criteria (from local technology buffs to subject matter experts in the field) or exciting new tweets is available from the convenience of a command line. Here are two final pieces of wisdom before I sign off: Twitter is serious about the hourly rate limits, so it's a good idea to have the search results cached in your code. Second, always check out Twitter's REST API resources, which your Twitter client lists with every API. Most of all, have fun with Twitter!

Resources

Learn

Get products and technologies

  • Find information on the Twitter Ruby API.
  • If you liked what you saw of Ruby in this article, check out the language's documentation.
  • Try out IBM software for free. Download a trial version, log into an online trial, work with a product in a sandbox environment, or access it through the cloud. Choose from over 100 IBM product trials.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into AIX and Unix on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=AIX and UNIX
ArticleID=769611
ArticleTitle=Accessing Twitter from the command line
publish-date=11082011