Mass Twitter unblock python script

I subscribe to several block lists on Twitter, as part of my efforts to avoid drama. One of the lists I subscribed to turned out to be much too aggressive, and I suspect that I’m blocking a bunch of people that I probably don’t really want to be blocking.

There are about 9000 people on this particular list, so unblocking them manually is highly impractical, and unsubscribing from the list does not unblock them. So I downloaded this list as a CSV file, and wrote a python script to go through it, automagically unblocking them for me.

A couple of features:

  • It unblocks 100 IDs, then pauses for 8 seconds, so as not to run afoul of the Twitter API rate limit.
  • The CSV that you get when you export your block list from Twitter, isn’t really a CSV, because there is only one column in the file, and no delimiters of any kind. So rather than import the CSV module and read the file as a CSV, I just have it reading the files like any text file. It works fine.
  • I wanted to get an email when it finishes the list, or when it encounters errors, so I pasted in an email function that I use quite a bit in other scripts.
  • This does require having a Twitter API key. There are many sites out there with instructions on how to obtain one, so I’m not going to cover that here. I already have several, as I have several Python scripts running a variety of Twitter tasks for me.
  • Added in some error handling.
  • Added command line arguments so that you specify the list file in the command line, and can optionally specify a line number to start from if the script bombs out partway through. This was happening frequently while I sorted out how to deal with trying to unblock deleted twitter accounts and such. Instead of erroring out, it now simply moves on to the next line. Not so much an issue now, but the capability is still there.

Usage: python3 twitterunblock.py <file.csv> <optional – starting line number>

#!/usr/bin/python3
# Author: DeadTOm - deadtom@deadtom.me
# License: GPLv2 - https://www.gnu.org/licenses/gpl-2.0.html
# Python Version: 3.6.1
# Description: Unblock a list of twitter IDs from a csv
# Usage: python3 twitterunblock.py <file.csv> <optional - starting line number>

from twython import Twython, TwythonError
import time
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
import sys

APP_KEY = ''
APP_SECRET = ''
OAUTH_TOKEN = ''
OAUTH_TOKEN_SECRET = ''

twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)

if len(sys.argv) == 2:  # Check to see what arguments were passed from the command line
   listfile = str(sys.argv[1])  # Get CSV file name from command line
   startingnum = 0  # Set the starting line number to zero, since none was specified
elif len(sys.argv) == 3:
   listfile = str(sys.argv[1])  # Get CSV file name from command line
   startingnum = int(sys.argv[2]) + 1  # Get the starting line number from the command line. Offset by one, because computers count from zero
else:  # If nothing was passed from the command line, print usage and exit
   print('Usage: python3 twitterunblock.py <file.csv> <starting line number>')
   sys.exit()


def unblock(blocklistfile, currentnum):
   linecount = 0
   global linenum  # Needed to modify the global variable, outside the function
   linenum = 0  # Keep track of line numbers when reading files
   global startingnum  # Needed to modify the global variable, outside the function
   startingnum = int(currentnum)  # Set starting num to the number passed to the function

   with open(blocklistfile) as blocklist:  # Open downloaded blocklist file, and iterate through each line
      for idnum in blocklist:
         if linenum >= startingnum:  # Skip lines we've already read
            startingnum = linenum  # Set the global variable "startingnum" to the current line number, so if the destroy_block command erros out, the function will know where to resume
            print('Line num: ' + str(linenum) + ' Line count: ' + str(linecount) + ' Unblocking ' + idnum)
            twitter.destroy_block(user_id=idnum)
            linecount += 1  # Increment linecount
            if linecount == 100:  # Every 100 lines, pause for eight seconds, then reset the counter
               time.sleep(8)
               linecount = 0
         else:
            print('Already unblocked ' + 'Line count: ' + str(linenum) + ' ' + idnum)
         linenum += 1  # Increment linenum


def sendmail(body, subj):  # Put together the mailer and send the message to me, using my mail server
   fromaddr = 'from@emailaddress'
   toaddr = 'to@emailaddress'

   msg = MIMEMultipart()
   msg['Subject'] = subj
   msg['From'] = fromaddr
   msg['To'] = toaddr

   msg.attach(MIMEText(body, 'plain'))

   server = smtplib.SMTP('mailserver', port)
   server.ehlo()
   server.starttls()
   server.ehlo()
   server.login('username', 'password')
   server.sendmail(fromaddr, toaddr.split(','), msg.as_string())
   server.quit()


try:
   unblock(listfile, startingnum)
   body = listfile + ' has been finished.'  # Set up the body for the email
   subj = 'Twitter unblock run finished - ' + listfile  # Set up the subject for the email
   sendmail(body, subj)
except TwythonError as oops:
   if '503' in str(oops):  # If a 503 error, wait five minutes and continue
      print('Encountered \"503\" error. Waiting five minutes, and continuing.')
      body = 'Error while running ' + listfile + ': ' + str(oops) + ' at line number ' + str(startingnum) + '\n Waiting five minutes and continuing...'  # Set up the body for the email
      subj = 'Twitter unblock run had an error - ' + listfile  # Set up the subject for the email
      sendmail(body, subj)  # Email the error message to me
      time.sleep(600)
      print('Starting over at line number ' + str(startingnum))
      unblock(listfile, startingnum)
   elif '404' in str(oops):  # If a 404 error, move to the next line number, and continue
      print('This user no longer exists, waiting sixty seconds and then skipping.')
      body = 'Error while running ' + listfile + ': ' + str(oops) + ' at line number ' + str(startingnum) + '\n Skipping user and continuing...'  # Set up the body for the email
      subj = 'Twitter unblock run had an error - ' + listfile  # Set up the subject for the email
      sendmail(body, subj)  # Email the error message to me
      startingnum += 1  # Increment startingnum, so as to skip the invalid ID number
      time.sleep(60)
      print('Starting over at line number ' + str(startingnum))
      unblock(listfile, startingnum)
   else:
      print(str(oops))
      body = 'Error while running ' + listfile + ': ' + str(oops)  # Set up the body for the email
      subj = 'Twitter unblock run had an error - ' + listfile  # Set up the subject for the email
      sendmail(body, subj)  # Email the error message to me

sys.exit()

You can download the script here.