Retweeting Revisited

Retweeting Revisited

So I cleaned up my twitter feed a little bit, by following my @CityOfSanJoseEN account.  I then noticed that our county, Santa Clara, does the same multi-lingual tweets:

I'm going to have my @CityOfSanJoseEN account do double duty.  I don't want to spend the extra time making a special account for @SCCgov, and I suspect anybody who follows my twitter account, will also find tweets from @SCCgov relevant.

For reference here's the code I was using to retweet the City of San Jose:

def main():
    api = twitter.Api(
        consumer_key=os.environ["TWITTER_API_KEY"],
        consumer_secret=os.environ["TWITTER_API_TOKEN"],
        access_token_key=os.environ["TWITTER_ACCESS_TOKEN"],
        access_token_secret=os.environ["TWITTER_ACCESS_TOKEN_SECRET"],
    )

    rts = api.GetUserRetweets()
    last_id_retweeted = None
    if rts:
        last_id_retweeted = rts[0].retweeted_status.id

    statuses = api.GetUserTimeline(
        screen_name="cityofsanjose",
        include_rts=False,
        count=100,
        since_id=last_id_retweeted,
    )

    logger.info(f"Found {len(statuses)} statuses")
    statuses.reverse()

    from retweeter.helpers import probably_english

    retweets = 0
    for status in statuses:
        if not probably_english(status.text):
            continue
        try:
            api.PostRetweet(status.id)
            retweets += 1
        except twitter.TwitterError as e:
            logger.error(e)

    logger.info(f"Retweeted {retweets} times")
https://github.com/davedash/retweeter/blob/sj-only/main.py

The bulk of the code is in a single method, which is nice, but we could benefit from some refactoring, and some code quality changes.  We could probably take the bulk of main() and put it into a method called retweet_account.

There's some other considerations, for example we looked at retweets to see what the last id was that we retweeted, but it doesn't take into account which account we are tweeting.  Turns out it doesn't matter.  Twitter IDs are roughly time ordered.  Meaning we can pass the same last_id_retweeted to both calls of api.GetUserTimeline we make for the various accounts.  This value can now serve as a type of bookmark for when we last ran our code.

So first, let's pull out the username:

  twitter_user = "cityofsanjose"
  statuses = api.GetUserTimeline(
    screen_name=twitter_user,
    include_rts=False,
    count=100,
    since_id=last_id_retweeted,
  )

Now let's pull out everything from `statuses = ` until the end of our method and make a new method:

def retweet_account(api, user, last_id):
    statuses = api.GetUserTimeline(
        screen_name=user,
        include_rts=False,
        count=100,
        since_id=last_id,
    )

    logger.info(f"Found {len(statuses)} statuses for {user}")
    statuses.reverse()

    retweets = 0
    for status in statuses:
        if not probably_english(status.text):
            continue
        try:
            api.PostRetweet(status.id)
            retweets += 1
        except twitter.TwitterError as e:
            logger.error(e)

    logger.info(f"Retweeted {user} {retweets} times")

We'll adjust the names of variables, and make the logs a bit more verbose.

Now we can call our new method from our main method:

    twitter_user = "cityofsanjose"

    retweet_account(api, twitter_user, last_id_retweeted)

Let's extend this to @SCCgov

    for user in ("cityofsanjose", "sccgov"):
        retweet_account(api, user, last_id_retweeted)
Scalability!

We can test this locally:

pipenv run python main.py
INFO:retweeter:Found 4 statuses for cityofsanjose
INFO:retweeter:Retweeted cityofsanjose 0 times
INFO:retweeter:Found 33 statuses for sccgov
INFO:retweeter:Retweeted sccgov 20 times

Looking at the twitter account it looks like we have some success.  Now our code is a bit more extensible.  In fact, by passing in the api object we can ostensibly retweet from multiple accounts.

The final code is on Github.

davedash/retweeter
Contribute to davedash/retweeter development by creating an account on GitHub.

Have a bot you need built, hit me up at build-a-bot@davedash.33mail.com