Collecting tweets using Python

MRT, Singapore

This article will demonstrate collecting tweets from the twitter streaming api. The data will be stored in a flat file for later analysis.

I will be using Ubuntu 13.10 for this article but if you have a working version of Python 2 and a python package manager you should be able to follow along.

Setting up tweepy, a python wrapper for the twitter api

For collecting tweets we will use the tweepy library which is a wrapper around the twitter api. To install:

pip install tweepy

Before you can access the twitter streaming api you need to register your client application (the python script) with Twitter. There is a tweepy authentication tutorial that explains step by step how to set up your app for oauth authentication.

Once you have registered with Twitter go to My Applications page on Twitter and you should see your newly created application. Click on the link and you should see the application details page:

show twitter applications

Let’s write a simple script to test the authentication.


Here is the output when I run the script in ipython:

ipython
Python 2.7.3 |CUSTOM| (default, Apr 12 2012, 11:28:34)
Type "copyright", "credits" or "license" for more information.

IPython 1.1.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.
Using matplotlib backend: MacOSX

In [1]: %run test_tweepy.py
Mark Kay

In [2]:

To give an idea of what you can do with the library just type ‘api.’ to see the methods available:

In [2]: api.
api.add_list_member                  api.mentions_timeline
api.api_root                         api.parser
api.auth                             api.rate_limit_status
api.blocks                           api.related_results
api.blocks_ids                       api.remove_list_member
api.cache                            api.report_spam
api.compression                      api.retry_count
api.create_block                     api.retry_delay
api.create_favorite                  api.retry_errors
api.create_friendship                api.retweet
api.create_list                      api.retweeted_by
api.create_saved_search              api.retweeted_by_ids
api.destroy_block                    api.retweets
api.destroy_direct_message           api.retweets_of_me
api.destroy_favorite                 api.reverse_geocode
api.destroy_friendship               api.saved_searches
api.destroy_list                     api.search
api.destroy_saved_search             api.search_host
api.destroy_status                   api.search_root
api.direct_messages                  api.search_users
api.favorites                        api.secure
api.followers                        api.send_direct_message
api.followers_ids                    api.sent_direct_messages
api.friends                          api.set_delivery_device
api.friends_ids                      api.show_friendship
api.friendships_incoming             api.show_list_member
api.friendships_outgoing             api.show_list_subscriber
api.geo_id                           api.subscribe_list
api.geo_search                       api.suggested_categories
api.geo_similar_places               api.suggested_users
api.get_direct_message               api.suggested_users_tweets
api.get_list                         api.test
api.get_oembed                       api.timeout
api.get_saved_search                 api.trends_available
api.get_status                       api.trends_closest
api.get_user                         api.trends_daily
api.home_timeline                    api.trends_place
api.host                             api.trends_weekly
api.last_response                    api.unsubscribe_list
api.list_members                     api.update_list
api.list_subscribers                 api.update_profile
api.list_timeline                    api.update_profile_background_image
api.lists_all                        api.update_profile_colors
api.lists_memberships                api.update_profile_image
api.lists_subscriptions              api.update_status
api.lookup_friendships               api.user_timeline
api.lookup_users                     api.verify_credentials
api.me

What to collect?

So now we have oauth working we can start to write the script to collect tweets and store them in a file so we can analyze them later.

Since I live in Singapore I am going to collect tweets from people at MRT stations.

MRT, Singapore

Why? No reason other than I can think of many ways to extract some useful information from the data. Examples are:

  • A proxy for population density
  • Geocoded tweets can be used to build a network map
  • Home/Work cycle can be calculated from data
  • Commute patterns?
  • Sentiment analysis, are people happy/sad/frustrated/mad at particular stations?

There are probably many other things that can be extracted from the data limited only by your imagination (and programming skills).

You can, of course, change the query to analyze anything you are interested in. Future articles I plan to write on data science and analysis will be based on this data.


Collecting tweets

We will use one of the public streams that is available through the Twitter API to listen in for tweets that are for a known MRT station. The track api allows us to track keywords, up to 400, which will be more than enough for our requirements. If you need to track more keywords Twitter has a number of partner providers here.

First of all, here is the script:

Python file: smrt_twitter.py

This script will write out each tweet received to an hourly tweet file. The entire data for the tweet in JSON format is written to disk. In addition, if the tweet is geocoded and contains a station name and number it is written to a separate file that can be used to generate a network map.

Tweets that don’t contain user information or are retweets are ignored.

Example of output (details changed):

Afvel Thompson
Wichita
web
20131218-11:30:06
'Samurai' man jumped gate, boarded train at Paya Lebar MRT

 ----------------

Found geo coords for MRT Station (EW6) 'kembangan mrt': (103.912830, 1.320984)

DumbasS

<a href="http://foursquare.com" rel="nofollow">foursquare</a>
20131218-11:34:32
I'm at Kembangan MRT Station (EW6) - @smrt_singapore (Singapore) http://t.co/Gjz8SSBgfy

 ----------------

Found geo coords for MRT Station (NE16) 'sengkang mrt': (103.895441, 1.391683)

shiyu

<a href="http://foursquare.com" rel="nofollow">foursquare</a>
20131218-11:34:43
I'm at Sengkang MRT/LRT Interchange (NE16/STC) (Singapore) http://t.co/cizUxPiLgd

 ----------------

Example of tweet data in json format (details changed):

{
    "created_at":"Wed Dec 18 09:34:43 +0000 2013",
    "id":XXXXXXXXXXXXXXXXXX,
    "id_str":"XXXXXXXXXXXXXXXXXX",
    "text":"I'm at Sengkang MRT\/LRT Interchange (NE16\/STC) (Singapore) http:\/\/t.co\/c1zUxPiLad",
    "source":"\u003ca href=\"http:\/\/foursquare.com\" rel=\"nofollow\"\u003efoursquare\u003c\/a\u003e",
    "truncated":false,
    "in_reply_to_status_id":null,
    "in_reply_to_status_id_str":null,
    "in_reply_to_user_id":null,
    "in_reply_to_user_id_str":null,
    "in_reply_to_screen_name":null,
    "user":{
        "id":XXXXXXXXXX,
        "id_str":"XXXXXXXXXX",
        "name":"shiyu",
        "screen_name":"xx_xxxxxxxx",
        "location":"",
        "url":null,
        "description":"One For All, All For One",
        "protected":false,
        "followers_count":45,
        "friends_count":115,
        "listed_count":1,
        "created_at":"Thu Mar 11 11:24:04 +0000 2013",
        "favourites_count":3385,
        "utc_offset":null,
        "time_zone":null,
        "geo_enabled":true,
        "verified":false,
        "statuses_count":7000,
        "lang":"en",
        "contributors_enabled":false,
        "is_translator":false,
        "profile_background_color":"642D8B",
        "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme10\/bg.gif",
        "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme10\/bg.gif",
        "profile_background_tile":true,
        "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/XXXXXXXXXXXXXXXXXX\/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX_normal.jpeg",
        "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/XXXXXXXXXXXXXXXXXX\/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX_normal.jpeg",
        "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/XXXXXXXXXX\/XXXXXXXXXX",
        "profile_link_color":"1717E6",
        "profile_sidebar_border_color":"FFFFFF",
        "profile_sidebar_fill_color":"7AC3EE",
        "profile_text_color":"3D1957",
        "profile_use_background_image":true,
        "default_profile":false,
        "default_profile_image":false,
        "following":null,
        "follow_request_sent":null,
        "notifications":null
    },
    "geo":{
        "type":"Point",
        "coordinates":[1.39168285, 103.89544129]},
        "coordinates":{
            "type":"Point",
            "coordinates":[103.80000000, 1.30000000]
        },
        "place":{"id":"96cff30292d71c41",
        "url":"https:\/\/api.twitter.com\/1.1\/geo\/id\/96cff30292d71c41.json",
        "place_type":"admin",
        "name":"Johor Bahru",
        "full_name":"Johor Bahru, Johore",
        "country_code":"MY",
        "country":"Malaysia",
        "contained_within":[],
        "bounding_box":
            {
                "type":"Polygon",
                "coordinates":
                    [
                        [
                            [103.5363541, 1.3416253],
                            [103.5363541, 1.673503],
                            [104.0161667, 1.673503],
                            [104.0161667, 1.3416253]
                        ]
                    ]
            },
        "attributes":{}
    },
    "contributors":null,
    "retweet_count":0,
    "favorite_count":0,
    "entities":{
        "hashtags":[],
        "symbols":[],
        "urls":[
            {
                "url":"http:\/\/t.co\/c1zUxP1Lge",
                "expanded_url":"http:\/\/4sq.com\/J40RLd",
                "display_url":"4sq.com\/J40RL3",
                "indices":[59, 81]
            }
        ],
        "user_mentions":[]
    },
    "favorited":false,
    "retweeted":false,
    "possibly_sensitive":false,
    "filter_level":"medium",
    "lang":"tl"
}

This is what the geocoded station data file looks like:

103.848310  1.350732    bishan mrt  NS17
103.848310  1.350732    bishan mrt  NS17
103.800749  1.440672    admiralty mrt   NS10
103.856120  1.300588    bugis mrt   EW12
103.849468  1.369641    ang mo kio mrt  NS16
103.839126  1.281345    outram park mrt EW16

Final Note

Twitter restricts publicly releasing datasets according to their API Terms of Service. However you can share derivative analysis from tweets, such as content analysis and aggregate statistics.

  • Prakhar Mohan

    So how do I get trending topics for a country? I can use trends_available() method to get the list of countries, from that I can extract a country, but after that how do I proceed?

    • Ravi Gurnatham

      import tweepy
      import json
      consumerKey =”r”
      consumerSecret =””
      accessToken = “”
      accessTokenSecret =””

      auth = tweepy.OAuthHandler(consumerKey, consumerSecret)
      auth.set_access_token(accessToken, accessTokenSecret)
      api = tweepy.API(auth)
      x=api.trends_place(here the country code )
      json_str=json.dumps(x)
      resp = json.loads(json_str) // resp is a json object from this you can extract whatever trending information of respective country by using their country code

  • Pingback: ENGL539 Designer Blog: (AP)I need a code | Ashley Hamouda()

  • VKB

    how to get ‘mrt_station_locations.csv’ data. ?