Tuesday, July 21, 2009

Python - Google Voice part 2

EDIT: Google recently made some behind the scenes changes to the login page, which broke this script. Please see the new and improved script here.

My last post was also about accessing your Google Voice account through Python, but there is more that you can do with it than just send SMS messages. You can make calls, cancel calls, view your call/sms/voicemail history and a few more others, as pointed out by this blogger here while talking about his Firefox plugin.

Since all of these options require you to be logged in, I thought that it would be easier to create a separate class that would:
1) Log you in and let you know whether or not your attempt was successful
2) Provide a method to get the "opener" (which is what keeps cookie data in order during multiple requests),
3) Provide a method to get your "_rnr_se" value, which is required when sending SMS messages, making calls, and canceling calls.

Instead of hardcoding in Google Account credentials like in my last post, the new class will prompt you for your Google Account user name and password. Since I want to use this script in public, I used the getpass module to hide the input as I type it. Here is the script:


# Get URL handling support
import urllib2, urllib
# Get regular expression support
import re, getpass

class GoogleVoiceLogin:
def __init__(self):
print "Please enter your Google Account credentials"
self.email = raw_input("User name: ")
self.password = getpass.getpass("Password: ")

# Set up an opener with HTTPCookieProcessor
self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
urllib2.install_opener(self.opener)

# Set up login credentials for Google Accounts
# The 'continue' param redirects us to the Google Voice
# homepage, and gives us necessary cookie info
loginParams = urllib.urlencode( {
'Email' : self.email,
'Passwd' : self.password,
'continue' : 'https://www.google.com/voice/account/signin'
} )

# Perform the login. Cookie info sent back will be saved, so we remain logged in
# for future requests when using the opener
self.opener.open( 'https://www.google.com/accounts/ServiceLoginAuth', loginParams)

# Need to load the homepage to find user specific data
googleVoiceHomeData = self.opener.open('https://www.google.com/voice/#inbox').read()

# Go through the home page and grab the value for the hidden
# form field "_rnr_se", which must be included when sending texts and dealing with calls
match = re.search('name="_rnr_se".*?value="(.*?)"', googleVoiceHomeData)
if not match:
print "Login Unsuccessful!"
exit()
else:
print "Login Successful!"
self._rnr_se = match.group(1)

def getOpener(self):
return self.opener

def getRnrSe(self):
return self._rnr_se


The script, for the most part, should be self-explanatory. It pretty much follows the same pattern as the script in my previous post except it is more reusable. For example, here is the new script I use to send text messages from the command line:


# Send a text Message
from GoogleVoiceLogin import GoogleVoiceLogin
import urllib

# Create an instance of a GoogleVoiceLogin object
# This will prompt you for your Google Account credentials
gvLogin = GoogleVoiceLogin()

# Get the open (Cookie data still intact)
opener = gvLogin.getOpener()

# Get the _rnr_se value
_rnr_se = gvLogin.getRnrSe()

# Prompt for Text Message details
phoneNumber = raw_input("Destination number: ")
text = raw_input("Message to send: ")

# Insert blank line
print

# Set up parameters for sending text
sendTextParams = urllib.urlencode({
'_rnr_se': _rnr_se,
'phoneNumber': phoneNumber,
'text': text
})

# Send the text, display status message
response = opener.open('https://www.google.com/voice/sms/send/', sendTextParams)
if "true" in response.read():
print "Message successfully sent!"
else:
print "Message failed!"
response.close()

Similar scripts could easily be created to call people, or perform other tasks on your account.

2 comments:

  1. Scott, not sure if you can help me, but I am pretty much a noob, but am working on an XML module for just sending calls with GV. As of now, I am using the XML from the google.com/voice/m interface for the call form, and just made it so it opens the calling window in a new window. But, I am having trouble retrieving the _rnr_se value which is needed for the form. Since the module will be running within a users google account, it should be as easy as parsing out the value from any of the google voice pages and then using the parsed var in the form. Unfortunately, I can't seem to make this work. If you could offer me any assistance on this very simple issue, I would much appreciate it, since this gadget is more for personal use than anything.

    ReplyDelete
  2. Ben -

    Sure thing. Since this post is about Python, and that is the only language I have used to access the "_rnr_se" so far, I can offer a Python solution.

    # Using regex to get the _rnr_se value
    import re
    # Use the urllib2 opener
    import urllib2, urllib
    # Set up an opener with HTTPCookieProcessor
    self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
    urllib2.install_opener(self.opener)

    # Set up login credentials for Google Accounts
    # The 'continue' param redirects us to the Google Voice
    # homepage, and gives us necessary cookie info
    loginParams = urllib.urlencode( {
    'Email' : email,
    'Passwd' : password,
    'continue' : 'https://www.google.com/voice/account/signin'
    } )

    # Perform the login. Cookie info sent back will be saved, so we remain logged in
    # for future requests when using the opener
    self.opener.open( 'https://www.google.com/accounts/ServiceLoginAuth', loginParams)

    # Need to load the homepage to find user specific data
    googleVoiceHomeData = self.opener.open('https://www.google.com/voice/#inbox').read()

    # Go through the home page and grab the value for the hidden
    # form field "_rnr_se", which must be included when sending texts and dealing with calls
    match = re.search('name="_rnr_se".*?value="(.*?)"', googleVoiceHomeData)

    _rnr_se = match.group(1)

    If you aren't using Python, you can still use that regular expression that I use. Just Use the regular expression on a page's contents that will contain the value.

    If that doesn't work, or you have a more specific question, go ahead and email me at [hillmanov at yahoo dot com].

    ReplyDelete

Please comment!