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:
聖塔克拉拉縣處於紅色風險級別,這意味著更多企業可以在室內營業。目前,一些室內企業和活動的風險仍然過高而不被允許營業。 pic.twitter.com/Om35G9KNuK
— Santa Clara County (@SCCgov) September 9, 2020
Santa Clara County is at Red Risk Level, meaning more businesses can operate indoors. Some indoor businesses and activities are still too high risk to allow at this time. pic.twitter.com/D7n2D1Vy83
— Santa Clara County (@SCCgov) September 8, 2020
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")
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)
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.
Have a bot you need built, hit me up at build-a-bot@davedash.33mail.com