I’ve revisited the code for Blogger posting with Python. Start here to see the new starting point.
The Original Tale
I want the ability to post to my blogs from the command line. That’s because I prefer to do everything from the command line, but that’s not really the point. The point is that I want an excuse to write a new quick script and satisfy that constant urge to gain some new superpower. Okay, so blogging’s not a superpower. Hush.
I’m writing this into a text file via Vim. It is written in a format known as Markdown, because I hate writing HTML by hand these days. It will eventually manifest as an HTML formatted post on my Blogger account.
All of the hard work is going to be done with Python. Why Python? Mainly because the [Google Blogger API][] is supported rather well by Python. They love their snake-based languages at Google, and it shows in the [GData Python Client][] library.
I could just as easily have used Perl or Ruby for this project. Heck, I could have used REBOL for this project if I was willing to craft some of the library by hand. All of these things are possibilities for the future. One thing I love to do is reimplement applications in various languages. It’s a sickness.
The Application Skeleton
Basic usage will be python post-to-blog.py post.txt. post.txt is a text file containing details like title or tags and the post body.
Here’s the basic pseudo-code that will work fine for simple posts.
Load global settings such as login and account URL
Create a local blog post based on the configuration and body from contents of post.txt
Request that Blogger publish this post.
Report the results of the request.
It’s fairly straightforward, but already shows me one class I’ll be using to mask the details:
I plan to use the doctest module to incorporate tests as I write this. It’ll get invoked if the script is run directly. I’ll put in some command line parsing later so that the tests can stillbe run but it doesn’t have to be the default behavior.
I already know what libraries I’m going to use, so let’s install those.
The GData Python Client, because that’s the whole reason I’m starting with Python instead of another language.
A Blogger account. Seemed obvious, but I thought I’d mention it.
I already have Python installed, so let’s move on to Markdown. It’s simple enough to install and verify.
Next I’ll install GData.
What can I do to verify this one? Let’s just run the provided sample Blogger code.
There’s a bunch of spew, and posts are made and deleted along with comments. Looks like it works.
Posting Formats
My blog post files will have a fairly straightforward layout, with a head section and a body section. It’ll look … well, it’ll look a lot like the lj-compose buffer in Emacs for composing Livejournal posts, now that I think about it.
The two sections are separated by a line containing only the characters --.
The head section uses a common format where each line contains a key and its value, with a colon and space combo : separating them. The keys and values in a blog posting contain details that are important to Blogger and unique to this particular file. Right now that means I’m only using title and tags.
I’ll just use commas for now when listing multiple values for a single key, such as with tags.
The body section is just Markdown-formatted text, including extensions that are available in the Python Markdown library.
Parsing the Config Header
There is a very handy ConfigParser class available in the Python standard libs, but it’s actually a little more than I need in a single post file. I just want to examine each line for key/value pairings without worrying about providing sections or a filehandle-like object
to make ConfigParser happy.
That was pretty easy, although I did have to do a little thinking to work around the fact that newline escapes tend to be read before doctest can get to them. Anyways, config lines are split on the : pair of characters. A regular expression might be better for general use but I’m still going for quick, dirty, and exactly what I want.
Parsing the Post Body
Now let’s get some HTML out of a block of Markdown-formatted text.
Those doctest tests are starting to look a little contorted. BlogPost.__config is really just dictionary, and I don’t really care whether it is private to the object. Let’s make the adjustments in __init__ and parseConfig. We don’t need getConfig now that we have direct access to the dictionary.
As long as we’re refactoring, I’d prefer it if the message body could be treated as a property. Setting it would store the string, while getting it would invoke markup and return the result.
Command Line Options
Before I get too carried away, I want to make sure that there are no ugly surprises in the formatting of my posts. Let’s do the heavy lifting with optparse.
You’ll have to just take my word for it that I wrote tests for each stage. Well, except for verifying that the final output looked roughly like what I hoped for. I’m not 100% sure how Markdown is going to place its newlines, so I am looking at the output via STDOUT:
I’ll save you the details of the full output. It looked about right, though.
Enough stalling. It’s time to login and post this article.
Interacting with Blogger
I’ll be using the official guide for Python and Blogger to choose my steps. You aren’t likely to find anything here that isn’t already there.
I haven’t figured out tags/labels yet, but let’s see how well this works. If you see this post, then I’ll know that Part 1 of my little quest is complete!
Um … okay, no. That didn’t work. I got a couple syntax and library errors, but after fixing those I still got an error code bX-y33b4h. This thread showed me that I wasn’t alone, but didn’t do much to solve my problem. I’ll have to look at the sample code that is in the python gdata distribution.
… later …
That posted, but I lost all the line breaks in my pre blocks. I decided to pick a new template, and that seemed to do the trick. I will definitely be fine tuning that template as I move along.
At some point I’ll figure out how to add labels.
The Code So Far
This is the code I used to publish this post. Definitely a work in progress - this version will submit your post as a draft, for example.