Time to up the ante on I built a RaspberryPi Twitter Bot. Because why not, that’s why!. Since the original post I moved the health monitoring of my Raspberry Pi’ to another system (more on that in another article). But I still wanted to have a Twitterbot.
But what should it tweet? Not being the most creative person in the world, I thought of German Bauernregeln. Really really badly transcribed into today’s ‘youth speak’ and I called them swag rules. I know I know, I can only fail in talking hip, but you know, you only live once and stuff (yolo, in case you missed it).
So I prepared a list of 250 something tweets, each one modernised Bauernregel. We’ll start with that, and it can easily be something totally different. You can have the bot tweeting the unix source code line for line, or Woody Guthries ‘This Land is your Land’ or of your course, your very own poetry.
All the basics are in place from the old Twitter-Bot. All tokens and key will be re-used (or set up new ones, to do so, follow the old guide). I’m also going to skip on pip install tweepy and virtualenv (the latter still highly recommended). If you have question marks over your head right now after reading the previous sentence, visit the old guide.
Let’s go – debugging
We do have a bit of debugging again here, to see if something goes wrong and where. Feel free to expand this into each of the try-except blocks and/or if-else-blocks:
fdebug_path = '/home/pi/Tweetbot/tweetlog.log' fdebug = open(fdebug_path, 'a') fdebug.write('\n' + time.strftime("%Y-%m-%d %H:%M:%S") + ' Starting \n') fdebug.write(time.strftime("%Y-%m-%d %H:%M:%S") + ' import time \n') fdebug.write(time.strftime("%Y-%m-%d %H:%M:%S") + ' import tweepy \n') fdebug.write(time.strftime("%Y-%m-%d %H:%M:%S") + ' import randint \n') fdebug.close()
Reading a tweet from file
Actually we need two files. One with the prepared tweets, and a 2nd one to store the tweets which have been tweeted (you can leave that of course if you don’t need a “record”).
fswagrules_path = '/home/pi/Tweetbot/swagrules.txt' ftweetedrules_path = '/home/pi/Tweetbot/tweetedrules.txt'
The script will read all rules (tweets) from the first file, and store them into a list during runtime. Be careful here, a file with thousands of lines means the same amount memory (RAM) will be used by the script. Don’t blow it! The Pi’s memory of course!
Then the script checks the length of the list (the number of possible tweets), and with this number randomly picks one, which will be tweeted:
try: fsr = open(fswagrules_path, 'r') all_rules = fsr.readlines() fsr.close() except: fdebug = open(fdebug_path, 'a') fdebug.write(time.strftime("%Y-%m-%d %H:%M:%S") + ' swag rules could not be opened\n') fdebug.close() if len(all_rules) > 0: number_of_rules = len(all_rules) rule_to_tweet = randint(0, number_of_rules - 1) tweet = all_rules[rule_to_tweet] tweet = tweet.rstrip() else: tweet = '' rule_to_tweet = 0
Try-except, because you never know with this file stuff. In the except part, a debug entry is written, because file access to read a tweet was not possible. In the following if-else section, the actual tweet is randomly selected using the length of the list of tweets. In case the length is 0, which means, the file was empty, or could not be accessed, tweet is set to an empty string.
And we use rstrip()-string function to remove the trailing line-break at the end of the tweet (because each line in the file of course has a line break at the end, which would be part of the string then, and we don’t want no line breaks ma’am).
Tweeting the tweet
Now a few words about the part of the script that does the
deed tweet. This time, the script will check if the tweet is going to be within the 140 character limit of twitter. If the tweet has more than 140 characters, it’s split up into several (even numbered) parts (stored as a list).
if len(tweet) > 0 and len(tweet) <= 140: api.update_status(status=tweet) elif len(tweet) > 140: tweetparts =  long_tweet = tweet while len(long_tweet) > 135: index = long_tweet.rfind(' ', 0, 135) tweetparts.append(long_tweet[0:index]) long_tweet = long_tweet[index:] tweetparts.append(long_tweet) j = len(tweetparts) for tweetstring in tweetparts: actual_tweet = str(tweetparts.index(tweetstring)+1) + '/' + str(j) + ':' + tweetstring api.update_status(status=actual_tweet) else: pass
If ‘tweet’ is empty nothing is tweeted. Obviously. D’uh. When the tweet is too long, the script searches for a white space backwards from the 135 character mark. This makes sure, that there is a bit of space to include a sequence number for the tweets then (1/2 & 2/2 for example). Split up the tweet into a list of (sub) tweet strings then, which a for-loop iterates over and tweets.
Removing the last tweet from the pool (and maybe adding it to the record).
The first part, you should definitely consider, because Twitter doesn’t want repeated tweets.
Thou shalst not tweet thy same tweets all over again.
That is why the script removes the tweet from the tweet-file with the following code (we do have the list of tweets anyway):
if len(all_rules) > 0: all_rules.pop(rule_to_tweet) if len(all_rules) > 0: all_rules[len(all_rules) - 1] = all_rules[len(all_rules)-1].rstrip() try: fsr = open(fswagrules_path, 'w') i = 0 while i < len(all_rules): fsr.write(str(all_rules[i])) i += 1 fsr.close() fdebug = open(fdebug_path, 'a') fdebug.write(time.strftime("%Y-%m-%d %H:%M:%S") + ' removed tweeded rule from swagrule pool\n') fdebug.close() except: fdebug = open(fdebug_path, 'a') fdebug.write(time.strftime("%Y-%m-%d %H:%M:%S") + ' swag rules could not be opened to remove tweeted rule\n') fdebug.close()
again, only done if there was a tweet at all. The string function .pop() will remove the tweet from the list. If the tweet was the last element of the list (and so of the file, where the last line does not have a trailing line break), the now new last element would have a trailing line break. I wanted this line break removed, because the record of tweets should be cleanly formatted. Of course, this if-section can only be done if, after poping the tweet from the list, the list isn’t empty (still with me? Good!).
The rest is just iterating over the list of remaining tweets and writing it into the file. Which is why we opened it in ‘w’-mode here to overwrite anything in it so far.
Optional: Recording tweets in a 2nd file
I thought maybe I wanted to use my Bauernregeln again, because they mean so much to me with the amount of work I put into them (haha). And maybe Twitter is okay if I repost them in half a year or so.
try: ftr = open(ftweetedrules_path, 'a') ftr.write(tweet + '\n') ftr.close() except: fdebug = open(fdebug_path, 'a') fdebug.write(time.strftime("%Y-%m-%d %H:%M:%S") + ' tweeted rules could not be written down\n') fdebug.close()
File access in a try-except section of course! And then it’s just adding the tweet as a new line to the record-file. Bada-boom. Bada-Bing. That’s it.
And here it is, my tweetbot with all its glorious Bauernregel, posted one every 12hours: https://twitter.com/FrankenBabo
Next step, make the Twitter bot listen for mentions.
- Full source for the Twitterbot v2 as “tweetbotv2.py” here: https://github.com/HerrSchroedinger/Tweetbotty