Tuesday, July 21, 2009

Redirect Python output

EDIT: Updated scripts to use the new login system described here.

Today at work I was working on a script to create some reports for one of my superiors. During my testing I was outputting everything to the screen so I could view it quickly and easily. My boss needed me to send him a file containing the data I was generating, and I didn't look forward to changing all of my print statements (
my script had many, many print statements) to something like "file.write(whateverwasbeingprintedbefore)". I could have done this, of course (and it could have been done in one easy step with the help of RegexBuddy) but that still seemed too inflexible of a solution. Python has a very simple solution for this problem, and it just takes an extra two lines of code.

My work example would have been boring here, so I thought up something else useful. Using my Google Voice Login class, I created another script to print out whatever is in my SMS inbox (up to the first 10) in a semi decent format. I used a couple of regular expressions, which I could not have created without RegexBuddy, to parse the page for the information I wanted. Here is that script (which requires the gvoice.py module I wrote):


# Print SMS inbox
from gvoice import GoogleVoiceLogin
import urllib
import re
import getpass

# Create an instance of a GoogleVoiceLogin object
# This will prompt you for your Google Account credentials
email = raw_input('Enter your Google Username: ')
password = getpass.getpass('Enter your password: ')

gv_login = GoogleVoiceLogin(email, password)

# Create our regular expressions (Created in RegexBuddy)
# Regular Expression to gather information on each SMS Conversation
sms_conversation_regex = re.compile(
r"""<span\sclass="gc-message-name">\s* # Get the message conversation info div
<span\sclass="">([^<]*?)</span>\s* # Get who originated the conversation
<span.*?</span>.*? # Eat this div - we don't need it
.*?>([^<]*).*? # Get who the conversation was started with
<div\sclass="gc-message-message-display">\s*
(<div\sclass="gc-message-sms-row">.*? # Get all the messages of the conversation
</div>\s*)* # Close up our divs
</div>""",
re.DOTALL | re.VERBOSE)

# Regular expression to gather information on individual messages within an SMS conversaion
sms_details_regex = re.compile(
r"""<div\sclass="gc-message-sms-row">.*? # Get up the message div
<span\sclass="gc-message-sms-from">\s*(.*?)\s* # Get who the message was from
</span>.*?
<span\sclass="gc-message-sms-text">\s*([^<]*)\s*.*?</div> # Get the message data""",
re.DOTALL | re.VERBOSE)

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

sms_inbox_content = opener.open("https://www.google.com/voice/inbox/recent/sms/").read()

# Nested for-loops of regular expressions - not the best way, but the easiest for now.
for sms_conversation_match in sms_conversation_regex.finditer(sms_inbox_content):
print
print "---{0} to {1} {2}".format(sms_conversation_match.group(1), sms_conversation_match.group(2), '-' * 50)
for message_details_match in sms_details_regex.finditer(sms_conversation_match.group()):
print "{0}: {1}".format(message_details_match.group(1), message_details_match.group(2))


Running this script will show you the first 10 SMS conversations in your inbox, if there are any. But, it is limited right now to displaying the information on the screen. Using these next two lines, you can put all of this information in a file of your choice:


import sys

sys.stdout = open("SMS Conversations.txt", "w")



To get this to work in the SMS inbox script, I insert the "import sys" command right below the other imports. The "sys.stdout" line goes right below the line where I instantiate the GoogleVoiceLogin object. I deliberately do that, otherwise I won't be able to see the prompt, because it will be written to the file!

This is a very easy way to change the output of your program - I hope you find it as useful as I did.

Here is the final script:

# Print SMS inbox
from gvoice import GoogleVoiceLogin
import urllib
import re
import sys
import getpass

# Create an instance of a GoogleVoiceLogin object
# This will prompt you for your Google Account credentials
email = raw_input('Enter your Google Username: ')
password = getpass.getpass('Enter your password: ')

gv_login = GoogleVoiceLogin(email, password)

sys.stdout = open("SMS Conversations.txt", "w")

# Create our regular expressions (Created in RegexBuddy)
# Regular Expression to gather information on each SMS Conversation
sms_conversation_regex = re.compile(
r"""<span\sclass="gc-message-name">\s* # Get the message conversation info div
<span\sclass="">([^<]*?)</span>\s* # Get who originated the conversation
<span.*?</span>.*? # Eat this div - we don't need it
.*?>([^<]*).*? # Get who the conversation was started with
<div\sclass="gc-message-message-display">\s*
(<div\sclass="gc-message-sms-row">.*? # Get all the messages of the conversation
</div>\s*)* # Close up our divs
</div>""",
re.DOTALL | re.VERBOSE)

# Regular expression to gather information on individual messages within an SMS conversaion
sms_details_regex = re.compile(
r"""<div\sclass="gc-message-sms-row">.*? # Get up the message div
<span\sclass="gc-message-sms-from">\s*(.*?)\s* # Get who the message was from
</span>.*?
<span\sclass="gc-message-sms-text">\s*([^<]*)\s*.*?</div> # Get the message data""",
re.DOTALL | re.VERBOSE)

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

sms_inbox_content = opener.open("https://www.google.com/voice/inbox/recent/sms/").read()

# Nested for-loops of regular expressions - not the best way, but the easiest for now.
for sms_conversation_match in sms_conversation_regex.finditer(sms_inbox_content):
print
print "---{0} to {1} {2}".format(sms_conversation_match.group(1), sms_conversation_match.group(2), '-' * 50)
for message_details_match in sms_details_regex.finditer(sms_conversation_match.group()):
print "{0}: {1}".format(message_details_match.group(1), message_details_match.group(2))
print "---{0} to {1} {2}".format(sms_conversation_match.group(1), sms_conversation_match.group(2), '-' * 50)
for message_details_match in sms_details_regex.finditer(sms_conversation_match.group()):
print "{0}: {1}".format(message_details_match.group(1), message_details_match.group(2))
blog comments powered by Disqus