A bit of Python to do draws on Twitter

23/09/2019Por iCarto

You can find on the Internet a lot of tips on how to organize a draws (sweepstakes) on Twitter, applications to do it (mostly paid) and the benefits of this type of marketing actions.

We simply wanted to draw a conference ticket without spending much time in the process and spread that we want to hire for development.

In this article we show fast and dirty how to obtain the identifiers of the people who made retweet to be able to choose one at random. We haven’t played with Twitter for a while, so the first question is whether Twitter still has an API that allows us to obtain this information easily.

A quick view of Duckduckgo that ends at StackOverflow plus a look at the endpoint index tells us that there are a couple of possible APIs to get the data:

  • GET statuses/retweeters/ids that would be exactly what we need. But that returns a maximum of 100 users. And it does not give us information that could be useful, such as the time of the retweet.
  • GET statuses/retweets/:id similar to the previous one, it gives us the retweet itself from which we can get the user. But again it is limited to a maximum of 100 retweets.
  • GET statuses/mentions_timeline which is a bit more complex to use and also has limits although higher. It also only works for the id that is logged, which complicates authentication a bit.

Given this, the best alternative seems to the API of retweets. If we see that we are approaching the limit we can make the request periodically and then filter. Or in case of problems, fallback to the mentions API or use it as double check .

The point now is what we need to use it. Generally these services require obtaining some type of development account, generating tokens, … The documentation (introductory) is “extensive” for an occasional user who simply wants to make a couple of API calls. But the summary is that it is necessary to request a development account by authenticating at https://developer.twitter.com/, and clicking on Create an app. If for some reason we had an old account with access to the API we can reuse the API Key of our old application. If not, we have to click on Apply, and fill in a non-small questionnaire, which includes filling in a text of a minimum of 200 words, and another four of at least 100 words. So, again, It’s not for casual user. So in our case we will reuse a API Key created long ago.

Entering the specific application there is a Keys and tokens tab where we will find an API key and an API secret key. Depending on what we want to do with the keys we will need to obtain a bearer token or an user access token . In our case we will only consult public information, at least as long as we do not use the mentions API, so we only need the bearer token.

The easiest way to test the API is using a command line utility created by Twitter called Twurl.

But doing it in Python is not complicated either. We could use some additional library to manage authentication but for something so simple we can do it by hand, simply using requests and without plugins.

The code dealing with authentication is as simple as this, where from API_KEY and API_SECRET_KEY (defined elsewhere) we get a bearer token and we will build the HTTP header that we will have to use in the rest of the requests.

def get_auth_headers(access_token=None):
    if not access_token:
        access_token = get_bearer_token()
    # TODO. It should be b64 encoded
    headers = {"Authorization": f"Bearer {access_token}"}
    return headers


def get_bearer_token():
    auth = (API_KEY, API_SECRET_KEY)
    endpoint = "https://api.twitter.com/oauth2/token"
    data = {"grant_type": "client_credentials"}
    r = requests.post(endpoint, data=data, auth=auth)
    r.raise_for_status()
    access_token = r.json().get("access_token")
    return access_token

Get the retweets and build a list of dictionaries with only the information of interest are also just a few lines.

def get_retweets(t_id, headers):
    endpoint = f"https://api.twitter.com/1.1/statuses/retweets/{t_id}.json"
    params = {"count": 100, "trim_user": False}
    r = requests.get(endpoint, params=params, headers=headers)
    r.raise_for_status()
    retweets = [
        {
            "created_at": retweet["created_at"],
            "id_str": retweet["id_str"],
            "user_id_str": retweet["user"]["id_str"],
            "user_name": retweet["user"]["name"],
            "user_screen_name": retweet["user"]["screen_name"],
        }
        for retweet in r.json()
    ]
    return retweets

And randomly choosing one of the items in the list is even simpler:

selected_retweet = random.choice(unique_retweets)

The complete script with the rest of boilerplate and executable from console is in this snippet.