Japanese Print

The Painter Goblin: Part 2, Twitter Pieces

Continuing the story from Painter Goblin part one, the idea of a Twitter bot started to form earlier this year.

The bare-bones of the Twitter bot were already somewhat in place, I run four bots as it is.

Each bot runs from the Python Anywhere service (pythonanywhere.com), see for example the output of binary-numbers: http://exponentialdecay.pythonanywhere.com/

The others send their output exclusively to Twitter via the scheduled tasks that can be run via it.

The Twitter API as discussed in previous work is provided by SixOhSix on GitHub.

The neat thing is that it is a bundled library in Python Anywhere and so it doesn’t take any extra work to install it when the code is uploaded to the server.


For those creating a Twitter Bot, it can be run from your regular account (you could run many!), but in most cases, you’ll create a dedicated account. Here I created:

To be able to automate your work Twitter needs to authenticate your code’s access. To do this we first register the app via http://apps.twitter.com/app/new

Register a Twitter Application

There are two files the Twitter API by SixOhSix uses to handle authentication with the service. A set of two consumer keys, and a set of two application keys.

Twitter Application Keys

With those in place you point the Twitter API to the information and off you go e.g. https://github.com/ross-spencer/painter-goblin/blob/master/twitterpieces.py#L12

Sending a Tweet becomes a two (or (see-below) three-step) process.

  • Create a Twitter object and authenticate
  • Send the Tweet via your new object

Changes since previous Twitter Bots

The API has changed since the last bot I created. It still has 140 character limits for posts. It also still shortens (or lengthens!) any URL of any length to 22 characters. This needs to be built into a heuristic when dynamically generating text for any Tweet we’re going to make.

A change that has really helped with making a bot is that images no longer count toward the 140 character limit. One less thing to think about! And a bonus for any bots that want to be more visual.

Uploading images is something I haven’t done before. Fortunately the SixOhSix README has a concise section on how toSend images along with your tweets’. Interestingly, to send an image with a Tweet is a three-step process, first it requires authentication, and then the image is uploaded to the Twitter dedicated server, which then returns an image key that is then sent with your text.

# Send images along with your tweets:

# - first just read images from the web or from files the regular way:
with open("example.png", "rb") as imagefile:
imagedata = imagefile.read()

# - then upload medias one by one on Twitter's dedicated server
# and collect each one's id:
t_upload = Twitter(domain='upload.twitter.com',
auth=OAuth(token, token_secret, consumer_key, consumer_secret))
id_img1 = t_upload.media.upload(media=imagedata)["media_id_string"]
id_img2 = t_upload.media.upload(media=imagedata)["media_id_string"]

# - finally send your tweet with the list of media ids:
t.statuses.update(status="PTT ★", media_ids=",".join([id_img1, id_img2]))

One issue discovered in testing was that the SixOhSix API version on Python Anywhere was behind that on GitHub – I’ve implemented legacy code to match versions on the server. I’ve also implemented the up-to-date mechanism so as to future-proof the code: https://github.com/ross-spencer/painter-goblin/blob/master/twittergoblin.py#L78

Lessons learned from before…

In creating this new code I wanted to make up for a few shortcomings. There were two design decisions I was able to incorporate, namely:

  • The ability to test Tweets with a –notweet flag
  • Improved ability to run code manually

The latter is a feature I was particularly keen on. While I like the idea of Painter Goblin as an art project, there are times it is nice to be able to run the process manually on special occasions for others, or at their request. Or just for fun to make new art for yourself.

We’ll see how this progresses in future posts as we get into the visual detail of the project.