Skip to content

Instantly share code, notes, and snippets.

@zakird
Last active December 17, 2015 14:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zakird/5625118 to your computer and use it in GitHub Desktop.
Save zakird/5625118 to your computer and use it in GitHub Desktop.
Module that provides a simple Pythonic interface to the Truthy twitter API. To use, place it in the folder named "truthy.py" in the same directory as your code.
#!/usr/bin/env python
"""
Module that provides a simple Pythonic interface to the Truthy twitter API.
Documentation on how the API works is available at https://www.mashape.com/truthy/truthy-1. This
library provides a very simple interface that hands back data from each of the Truthy API endpoints
and manages pagination. Each class (TruthyMemes, TruthyNetworks, TruthyTimelines, TruthyUsers) has
a single method `get` which accepts all of the parameters defined by the Truthy API and returns
all results. API exceptions are all children of APIError. Note that because this library manages
pagination, none of the library calls accept the offset parameter defined by the API documentation.
Instead, each accept a `max_records` parameter.
Requirements:
1. unirest (http://unirest.io) (`easy_install unirest`)
2. You will need to register for a mashape (https://www.mashape.com/) account
and create an API key that you can use to run queries.
Example:
1. Find the most popular hashtags about Obama
import truthy
key = "XXXXXX"
t = TruthyMemes(key)
for l in t.get(text__icontains="obama", order_by="-num_tweets", max_records=1000):
if l["meme_type"] == "hash_tag":
print l["text"], l["num_tweets"]
"""
__author__ = "Zakir Durumeric, University of Michigan"
__email__ = "zakir@umich.edu"
__license__ = "Apache 2.0"
import sys
import urllib
try:
import unirest
except Exception, e:
print "ERROR: unable to import unirest. You may need to run `easy_install unirest`."
sys.exit(1)
class APIError(Exception):
"""Base exception class for any errors thrown by the Truthy API"""
def __init__(self, e):
self.e = e
def __str__(self):
return repr(self.e)
class TruthyBase(object):
def __init__(self, api_key):
assert(api_key)
self._api_key = api_key
def __make_path(self, vals):
"""make request into a valid REST request URL"""
# child classes must define a URL
assert hasattr(self, "_url") and getattr(self, "_url")
# filter out all of the parameters that have null values.
# we don't need to pass null arguments in the REST call
non_null = dict((k,v) for (k,v) in vals.iteritems() if v is not None)
params = urllib.urlencode(non_null)
return "%s?%s" % (self._url, params)
def __get(self, **kwargs):
"""make REST request and return parsed data"""
return unirest.get(self.__make_path(kwargs),
{"X-Mashape-Authorization": self._api_key}
).body
def _iterget(self, **kwargs):
assert "offset" not in kwargs
kwargs["offset"] = 0
i = 0
while True:
r = self.__get(**kwargs)
# it appears that the API will pass you back two dicts, meta and objects
# if the API call is successful. otherwise, if there's an error, you just
# get back a single string.
if r.__class__.__name__ == "str":
raise APIError(r)
if not i:
print >> sys.stderr, "INFO: total number of records: %i" % r['meta']['total_count']
first = False
if not r['objects']:
break
for l in r['objects']:
yield l
if "max_records" in kwargs and i > kwargs["max_records"]:
return
i += 1
kwargs['offset'] = r['meta']['next-offset']
class TruthyMemes(TruthyBase):
"""Statistics about Memes (#hashtag, @user, http://url, or "phrase")
for the past 90 days of Twitter communication."""
_url = "https://truthy-public.p.mashape.com/memes"
def get(self, **kwargs):
"""
text__icontains: Restricts the return query to those memes that contain the given text. Case insensitive.
meme_id: The id for the meme
num_users__gt: Restricts query to memes that have at least N number of users
num_tweets__gt: Restricts query to memes that have at least N number of tweets
last_event_ts__gt: Restricts query to memes that have at least one event since the given time
Example: 2013-02-16T02:07:05
meme_type: The type of the meme.
Example: hash_tag, mention, tweet_text, url
order_by: Orders by the given field. Add negative sign in front for descending order.
Example: -num_tweets
max_records: Maximum number of records you want to process
"""
for r in self._iterget(**kwargs):
yield r
class TruthyNetworks(TruthyBase):
"""Meme communication networks in various formats (gexf, graphml, edgelist, adjlist).
These are calculated daily from the past 90 days of Twitter communication.
Not computed for memes with low activity levels."""
_url = "https://truthy-public.p.mashape.com/networks"
def get(self, **kwargs):
"""
ext: (required) The format of the network layout.
Example: graphml, gexf, edgelist, or adjlist
meme_id: The unique identifier of the meme
max_records: Maximum number of records you want to process
"""
for r in self._iterget(**kwargs):
yield r
class TruthyTimelines(TruthyBase):
"""Data over time for particular memes"""
_url = "https://truthy-public.p.mashape.com/networks"
def get(self, **kwargs):
"""meme_id: The unique identifier of the meme"""
for r in self._iterget(**kwargs):
yield r
class TruthyUsers(TruthyBase):
"""" A user who has at least one tweet on the memes we track.
We offer statistics about them such as political partisanship detection,
sentiment analysis, and activity levels. All users are anonymous."""
_url = "https://truthy-public.p.mashape.com/networks"
def get(self, **kwargs):
"""
meme_id: Restricts query to the users who have at least one tweet about a particular meme.
user_id: The user with the id we are looking for
format: The format of the request
order_by: Orders by the given field. Add negative sign in front for descending order.
max_records: Maximum number of records you want to process
"""
for r in self._iterget(**kwargs):
yield r
def main():
key = "XXXXXX"
t = TruthyMemes(key)
for l in t.get(text__icontains="obama", order_by="-num_tweets", max_records=10):
if l["meme_type"] == "hash_tag":
print l["text"], l["num_tweets"]
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment