Jan 072016
 
Twitter tweepy raspberry pi app

I’m a firm believer that you should always test things in advance. It helps avoid unexpected last-minute panics when things don’t work as you expected them to. On Friday I’m going to pick a winner from my twitter followers using the twitter app script I wrote back in October 2013.

It Still Works, But…

Since I had no idea where the SD card with that old Raspbian image was, I decided this would be an ideal opportunity to check that the script is still current and working as it should. You’ll be glad to hear that the instructions still work fine and the original script still works. But – yes there’s always a but – I have a lot more twitter followers than I did two years ago and I stumbled across an issue that only kicks in once you have >5000 followers.

I ran the original script and it told me I had exactly 5000 followers. I knew this to be wrong because yesterday I hit 9000 (you tend to notice the even milestones). Why could this be happening? Is it a limitation of tweepy? Some googling revealed that the twitter API is rate-limited. In terms of querying followers it will only allow you to query 5000 followers once per minute, so you have to split your query into sections <=5000.

How To Search More Than 5000 Followers In Tweepy?

It’s easy and obvious when you know, but actually finding out how to do this was quite tricky. It took several rounds of looking at the tweepy documention, the twitter API documentation and stack exchange to work out the code that would do the job for me. In truth, I would never have worked it out from the documentation because it is too hard to understand and there are too few useful examples. This code snippet on stack exchange saved the day for me, but it took a long time to find it. Lines 9 onwards are the interesting bits…

import time
import tweepy

auth = tweepy.OAuthHandler(..., ...)
auth.set_access_token(..., ...)

api = tweepy.API(auth)

# this is the part I actually used, changing McDonalds to raspitv...
ids = []
for page in tweepy.Cursor(api.followers_ids, screen_name="McDonalds").pages():
    ids.extend(page)
    time.sleep(60)

print len(ids)

Documentation Without Examples Is Almost Useless (to me)

This code allows you to Cursor() through multiple pages() of results. I’d seen reference to Cursor() and pages() in both tweepy and Twitter API documention, but it was incomprehensible to me. All I needed was 4 lines of code in an example. A well explained example is worth far more than generalised documentation.

So how does it work? It loops through the pages() of follower_ids, waiting 60 seconds in between each page. Each page is added to the ids list. Once finished, it tells you how many entries there are in the ids list.

1 Minute Delay Per 5000 Followers

This was exactly what I needed! So I tweaked my script to incorporate this code, and it now works as it should. If used on an account with a very large number of followers it will take a long time to run, as it waits 65 seconds between each page of 5000 followers. To run this script for the official @Raspberry_Pi twitter account (with 257k followers) would take >55 minutes (and it might well break something else – WJDK).

Here’s The Code

This script now works and is fit for purpose…

#!/usr/bin/env python2.7
# twitdraw.py based on twitterwin.py by Alex Eames https://raspi.tv/?p=5281
import tweepy
import random
from time import sleep

# Consumer keys and access tokens, used for OAuth
consumer_key = 'insert_your_consumer_key'
consumer_secret = 'insert_your_consumer_secret'
access_token = 'insert_your_access_token'
access_token_secret = 'insert_your_access_token_secret'

# OAuth process, using the keys and tokens
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)

# Creation of the actual interface, using authentication
api = tweepy.API(auth)

user = api.get_user('raspitv')
print user.screen_name
print user.followers_count

ids = []
for page in tweepy.Cursor(api.followers_ids, screen_name="raspitv").pages():
    ids.extend(page)
    if len(page) == 5000:
        print "waiting 65 seconds before requesting next page of results..."
        sleep(65)

print "you have %d followers" % len(ids)

show_list = raw_input("Do you want to list the followers array?")
if show_list in ('y', 'yes', 'Y', 'Yes', 'YES'):
    print ids

def pick_winner():
    random_number = random.randint(0, len(ids)-1)
    winner = api.get_user(ids[random_number])
    print winner.screen_name, random_number

while True:
    pick = raw_input("Press Enter to pick a winner, Q to quit.")
    if pick in ('q', 'Q', 'quit', 'QUIT', 'Quit'):
        break
    pick_winner()

(Edit to add: Thanks to Andrew Scheller for comment 1 below. Most of those tips have been incorporated to improve the code.)

Odd SSL Error

The only other thing that isn’t quite as it ought to be is that there is an odd SSL error message appearing in the output for each tweepy query. There doesn’t appear to be much I can do about this – apart from switching to twython – which I probably will do at some point anyway. But for now, it works, so I don’t much care about that.

Script output including SSL errors (some cut out)

Script output including SSL errors (some cut out)

And Tomorrow We Use It For Real!

Tomorrow I will use this script to pick a winner at random from my twitter followers. The winner will receive a Joey board from Gooligum Electronics

If you fancy having a go at this yourself, start with the original page here which has all the installation instructions on.

  7 Responses to “Always Test Everything – Twitter App Update”

  1. I don’t use Twitter myself, but here’s a few little Python tips… ;-)

    raw_input always returns a string, so no need to explicitly do str(raw_input())

    if show_list == (‘y’ or ‘yes’ or ‘Y’ or ‘Yes’ or ‘YES’):
    doesn’t actually do what you think it does! (‘y’ or ‘yes’ or ‘Y’ or ‘Yes’ or ‘YES’) will always return ‘y’ (as it’s the first non-False value), so your if-statement is actually just doing
    if show_list == ‘y’:
    You can verify this by typing
    ‘yes’ == (‘y’ or ‘yes’ or ‘Y’ or ‘Yes’ or ‘YES’)
    into an interactive python prompt (and the same obviously applies to the ‘pick’ line too).
    To get it to do what you *expect* it to do, you could rewrite it as
    if show_list in (‘y’, ‘yes’, ‘Y’, ‘Yes’, ‘YES’):
    or just simplify it to
    if show_list[0].lower() == ‘y’:

    For choosing a single random item out of an array, it’s probably easier to use https://docs.python.org/2/library/random.html#random.choice i.e. you could do
    random_id = random.choice(ids)
    winner = api.get_user(random_id)

    print “Happy New Year %d!” % (2**5*3**2*7)

    • Thanks Andrew. I’ll do some tweaks. Some basic stuff there that has gone unnoticed for >2 years as it’s mostly copied from the original script. :)

      • Great :)
        It currently works as-is, but I think line 34 would look better with a space after the ‘in’.

        Bugs that are copy’n’pasted from existing code are always very easy to overlook, and tend to be the kind of things that only a fresh pair of eyes can spot ;-)

        • **Swears**
          **adds space**

          Thanks Andrew. I agree with you. It was unintentional. I’ve gone back and “reto-fitted” the amendments to the original script as well :)

  2. Alex, your SSL errors are pretty easy to fix. I followed your guide to install tweepy, then wrote a follow-up post on a blog detailing how to correct the errors. That post is here: http://bottomdrawerprojects.blogspot.com/2016/02/tweeting-from-your-pi-fixing-issues.html

  3. Thanks for the great tutorial Alex. Agreed the Tweepy docs are very slim.

    I would just add the “name” when you print out the winner. Its easier to find on your feed than the “screen_name”.
    i.e. print winner.screen_name, random_number, ” – Name: “, winner.name

Leave a Reply