Entry for August 30, 2007= pause on Python, info on Twitter

11.3. Advantages and Disadvantages
Twitter is an attractive option for implementing an SMS service because it's free and comes with a built in user base and social network. You don't need a web server to create a Twitter mashup, either, just a machine with an Internet connection.
On the other hand, anyone who wants to use your service must first become a member of Twitter. This isn't really that big of a deal, though, when you consider that some kind of registration system is required for most services.
The other big downside to using Twitter is that your service must be addressed by name (e.g., "d yourservicename message") on every message, making interactions more complex and arduous. Twitter also takes up a bit of your character limit with reply instructions (but it's nothing compared to the extras 411Sync adds in).
___________________________________________________
11.4.2. Functionality
Our Twitter interface provides most of the functions that you'll want to use to implement a Twitter service. Some of them are documented in the public API, but some of them are not. Here are the methods we'll be using:
get_followers (public): Gets a list of users that are following you. People who are following you will hear your messages. http://twitter.com/statuses/followers.json
get_friends (public): Gets a list of users that you consider your friends—you'll receive their updates and their direct messages. http://twitter.com/statuses/friends.json
get_direct_messages (public): Returns every (non-deleted) direct message you've ever received. (Ideally there would be a function just to return unread messages, but it doesn't exist as of this writing.) http://twitter.com/direct_messages.json
befriend_all (undocumented): This function makes everyone who is following you your friend. This is important because in Twitter, you can only receive message from people who are your friends. http://twitter.com/followers/befriend_all
send_direct_message (public): Given a user name or id and a message to send, this method will send the message to the user - provided that user has accepted you as a friend. As noted in the API documentation, this method must be called using POST. http://twitter.com/direct_messages/new.json
delete_direct_message (undocumented): Lets you delete a message, given its message id. A service needs to delete messages every time it reads them to avoid acting twice on the same message. http://twitter.com/direct_messages/destroy/[MessageID]
delete_one_page_of_sent_messages (undocumented): Gets the Message IDs of all the sent messages that will show up on the user's sent direct message panel. It uses the IDs and repeatedly calls delete_direct_message. There might be a better way of doing this, but as of this writing it is the best mechanism we could find. http://twitter.com/direct_messages/sent(This is normal user-visible page, not an API call.)
twitter.py:
(once again, no indents, sorry)
#!/usr/bin/python
import sys
import os
import urllib2
import urllib
import json
import time
import re
import random
TWITTER_URL = "http://twitter.com"
class Twitter(object):
def __init__(self, useremail, password):
authstring = "%s:%s"%(useremail, password)
self.__twitter = urllib2.build_opener()
self.__twitter.addheaders = [
('Authorization', 'Basic %s'% (authstring.encode("base64").strip()))
]
self.__sent_destroy_re = re.compile("/direct_messages/destroy/([0-9]+)")
def get_followers(self):
page = self.__twitter.open(TWITTER_URL + "/statuses/followers.json")
return json.read(page.read())
def get_friends(self):
page = self.__twitter.open(TWITTER_URL + "/statuses/friends.json")
return json.read(page.read())
def befriend_all(self):
page = self.__twitter.open(TWITTER_URL + "/followers/befriend_all")
def get_direct_messages(self):
page = self.__twitter.open(TWITTER_URL + "/direct_messages.json")
return json.read(page.read())
def send_direct_message(self, friend_id, text):
params = {
'text' : text,
'user' : friend_id,
}
page = self.__twitter.open(TWITTER_URL + "/direct_messages/new.json",
data=urllib.urlencode(params))
return json.read(page.read())
def delete_direct_message(self, direct_message_id):
page = self.__twitter.open(TWITTER_URL + "/direct_messages/destroy/%s"
% direct_message_id)
def delete_one_page_of_sent_messages(self):
page = self.__twitter.open(TWITTER_URL + "/direct_messages/sent")
for line in page.readlines():
m = self.__sent_destroy_re.search(line)
if m:
self.delete_direct_message(m.group(1))
def main():
#simple usage example
twit = Twitter("username", "password")
print twit.get_friends()
if __name__ == '__main__':
main()
__________________________________________________________
er requires that most commands be authenticated using Basic Authentication. The constructor builds an object that will attach the appropriate authorization header every time we make a request. The code inside the constructor for Twitter base64 encodes the text "username:password" and then puts it in an "Authorization" header prefixed with the word "Basic." You can read more about Basic Authentication at http://www.ietf.org/rfc/rfc2617.txt.
Almost every method simply uses the opener we created in the constructor to access one URL. The URL returns a JSON dictionary that we convert into a python dictionary.
The .json appended to the URL tells Twitter to return the results as JSON dictionaries. XML and RSS are supported for many methods as well. JSON was chosen here because it is lightweight and translates easily into Python dictionaries. All we have to do is call the read method of the JSON module on the results, and we get a Python dictionary back with all the results
A JSON dictionary for a get_friends call looks something like this (this user has one friend named testinos:
[{"name":"testinos","description":null,"location":null,
"profile_image_url":"http:\/\/assets0.twitter.com\/images\/
default_image.gif?1181015407","url":null,"id":5719462,
"screen_name":"testinos","protected":false}]
After calling json.read() on the text of the JSON, we get a Python dictionary that looks like this:
[{'name': 'testinos', 'url': None, 'profile_image_url':
'http://assets0.twitter.com/images/default_image.gif?1181015407',
'screen_name': 'testinos', 'location': None, 'protected': False,
'id': 5719462, 'description': None}]
There are a few methods that warrant some additional explanation:
The Twitter API requires that POST be used when sending direct messages. The opener knows to use POST instead of get when it's passed a urlencoded string as the second parameter to open. You'll notice in the send_direct_message function that we call urlencode on a parameter dictionary for just that purpose
The delete_one_page_of_sent_messages function has to load a normally user-visible web page in order to do its duty. This is because there is no API call to retrieve sent messages. A regular expression extracts the Message ID for each sent