Пример #1
0
 def __init__(self,username,password,racismPhraseFilePath,raceFilePath,repliedFilePath,verbose=False,reply=True):
     self.verbose = verbose
     if self.verbose:print("[*] Antiracism_Bot v."+__version__)
     if self.verbose:print("[*] Initialising new Bot")
     if self.verbose:print("[*] Verbose mode activated")
     self.reply = reply
     if self.verbose:
         if reply:
             print("[*] Bot will reply")
         else:
             print("[*] Bot will not reply")
     self.running = True
     self.r = praw.Reddit(USER_AGENT)
     self.username = username
     if self.verbose:print("[*] Logging in as "+username)
     try:
         self.r.login(username,password)
         if self.verbose:print("[+] Login successful")
     except:
         if self.verbose:
             print("[!] Login failed")
             print("[*] Setting reply to false")
             self.reply = False
         
     self.racismFilePath = racismPhraseFilePath
     self.raceFilePath = raceFilePath
     self.repliedFilePath = repliedFilePath
     self.racismKeyPhrases = {} # racistPhrase:(reason,value)
     self.races = []
     if self.verbose:print("[*] Populating racism table")
     self.populateRacismDict()
     if self.verbose:print("[*] Racist table contains "+str(len(self.racismKeyPhrases))+" entries")
     self.alreadyDone = set()
     if self.verbose:print("[*] Reading previously made comments")
     self.readAlreadyDone()
     self.todo = DataStructure()
     self.todoIDs = []
Пример #2
0
class RacismChecker(object):
    '''
    Finds racism on the internet
    '''
    def __init__(self,username,password,racismPhraseFilePath,raceFilePath,repliedFilePath,verbose=False,reply=True):
        self.verbose = verbose
        if self.verbose:print("[*] Antiracism_Bot v."+__version__)
        if self.verbose:print("[*] Initialising new Bot")
        if self.verbose:print("[*] Verbose mode activated")
        self.reply = reply
        if self.verbose:
            if reply:
                print("[*] Bot will reply")
            else:
                print("[*] Bot will not reply")
        self.running = True
        self.r = praw.Reddit(USER_AGENT)
        self.username = username
        if self.verbose:print("[*] Logging in as "+username)
        try:
            self.r.login(username,password)
            if self.verbose:print("[+] Login successful")
        except:
            if self.verbose:
                print("[!] Login failed")
                print("[*] Setting reply to false")
                self.reply = False
            
        self.racismFilePath = racismPhraseFilePath
        self.raceFilePath = raceFilePath
        self.repliedFilePath = repliedFilePath
        self.racismKeyPhrases = {} # racistPhrase:(reason,value)
        self.races = []
        if self.verbose:print("[*] Populating racism table")
        self.populateRacismDict()
        if self.verbose:print("[*] Racist table contains "+str(len(self.racismKeyPhrases))+" entries")
        self.alreadyDone = set()
        if self.verbose:print("[*] Reading previously made comments")
        self.readAlreadyDone()
        self.todo = DataStructure()
        self.todoIDs = []
        
    def shutdown(self):
        self.saveAlreadyDone()
        self.running = False
        
    def populateRacismDict(self):
        '''
        Fills table from files
        '''
        racismTable = {}
        if self.verbose:print("\t[*] Reading "+self.raceFilePath)
        with open(self.raceFilePath) as raceFile:
            for raceLine in raceFile:
                raceLine = raceLine.strip()
                if raceLine[0]!="#":
                    self.races.append(raceLine)
        if self.verbose:print("\t[*] Race file contains "+str(len(self.races))+" races")
        if self.verbose:print("\t[*] Reading "+self.racismFilePath)
        with open(self.racismFilePath) as racismFile:
            for racismLine in racismFile:
                # Space on each side should prevent [jap]anese from alert
                racismLine = racismLine.strip()
                if racismLine[0]!="#":
                    if racismLine.find(":")>-1:
                        value = int(racismLine[:racismLine.find(":")])
                        racismLine = racismLine[racismLine.find(":")+1:]
                        reason = racismLine[:racismLine.find(":")]
                        racismLine = racismLine[racismLine.find(":")+1:]
                        if "[RACE]" in racismLine:
                            recRacismTable = self.raceRecursion(racismLine)
                            for phrase in recRacismTable:
                                racismTable[phrase.lower()] = (reason.lower(),value)
                        else:
                            # ALL LOWER CASE!
                            racismTable[racismLine.lower()] = (reason.lower(),value)
                    else:
                        if self.verbose:print("\t[!] Failed to parse: "+racismLine)
        if self.verbose:print("\t[*] Constructed "+str(len(racismTable))+" racist phrases")
        self.racismKeyPhrases = racismTable
                    
    def raceRecursion(self,line):
        '''
        Through recursion should replace all [RACE]s with all permutations
        '''
        newRaceLineTable = []
        if "[RACE]" in line:
            for race in self.races:
                    newLine = line.replace("[RACE]", race, 1) # removes 1 [RACE] token
                    if "[RACE]" in newLine:
                        newRaceLineTable = newRaceLineTable + self.raceRecursion(newLine)
                    else:
                        newRaceLineTable.append(newLine)
        return newRaceLineTable
    
    def subredditLoop(self,subredditName):
        '''
        Check specific subreddit(s) for racism and replies
        '''
        if self.verbose:print("[*] Checking subreddits: "+subredditName)
        while self.running:
            try:
                subreddit = self.r.get_subreddit(subredditName)
                subredditComments = subreddit.get_comments(limit=None)
                self.commentLoop(subredditComments)
                self.manageTODOs()
                self.saveAlreadyDone()    
                time.sleep(2)
            except Exception as e:
                if self.verbose:print("[!] Exception: "+e.message)
                reportException(e)
                    
    def allLoop(self):
        '''
        Check everything for racism
        '''
        if self.verbose:print("[*] Checking all subreddits")
        while self.running:
            try:
                all_comments = self.r.get_comments("all",limit=None)
                self.commentLoop(all_comments)
                self.manageTODOs()
                self.saveAlreadyDone()
                time.sleep(2)
            except Exception as e:
                if self.verbose:print("[!] Exception: "+e.message)
                reportException(e)
    
    def subredditCommentParsing(self,subredditName,sleepTime=2):
        '''
        Just reads and parses comments for subreddit, does not autoreply
        '''
        if self.verbose:print("[*] Starting comment parsing")
        while self.running:
            try:
                subreddit = self.r.get_subreddit(subredditName)
                subredditComments = subreddit.get_comments(limit=None)
                self.commentLoop(subredditComments,addTODO=True)
                time.sleep(sleepTime)
            except Exception as e:
                if self.verbose:print("[!] Exception: "+e.message)
                reportException(e)
                
    def allCommentParsing(self,sleepTime=2):
        '''
        Just reads and parses comments for all subreddits, does not autoreply
        '''
        if self.verbose:print("[*] Starting comment parsing")
        while self.running:
            try:
                all_comments = self.r.get_comments("all",limit=None)
                self.commentLoop(all_comments,addTODO=True)
                time.sleep(sleepTime)
            except Exception as e:
                if self.verbose:print("[!] Exception: "+e.message)
                reportException(e)
    
    def replyManager(self,sleepTime=10):
        '''
        Just replies to TODOs, does not read comments
        '''
        if self.verbose:print("[*] Starting reply serving")
        while self.running:
            try:
                self.manageTODOs()
                self.saveAlreadyDone()
                time.sleep(sleepTime)
            except Exception as e:
                if self.verbose:print("[!] Exception: "+e.message)
                reportException(e)
    
    def manageTODOs(self):
        while self.todo.hasNext():
            try:
                comment, replyText = self.todo.pop()
                subredditname = unicodedata.normalize('NFKD', comment.subreddit.display_name).encode('ascii','ignore')
                if self.reply:
                    comment.reply(replyText)
                    if self.verbose:print("[+] Replied to comment "+comment.id+" in /r/"+subredditname+":\n"+replyText)
                else:
                    if self.verbose:print("[+] Would reply to comment "+comment.id+" in /r/"+subredditname+":\n"+replyText)
                self.alreadyDone.add(comment.id)
                self.todoIDs.remove(comment.id)
            except praw.errors.RateLimitExceeded:
                return
    
    def readAlreadyDone(self):
        with open(self.repliedFilePath) as repFile:
            for line in repFile:
                line = line.strip()
                if line!="":
                    self.alreadyDone.add(line)
    
    def saveAlreadyDone(self):
        with open(self.repliedFilePath,"w") as repFile:
            for a in self.alreadyDone:
                repFile.write("\n"+a)
    
    def commentLoop(self,comments,addTODO=False):
        for comment in comments:
            (commentisracist, quotes) = self.checkIfCommentIsRacist(comment.body.lower())
            if commentisracist and comment.author.name.lower()!=self.username.lower() and comment.id not in self.alreadyDone and comment.id not in self.todoIDs:
                replyText = "Your comment contains "
                reasonDict = {}
                totalValue = 0
                for quote in quotes:
                    key = self.racismKeyPhrases[quote] #key = (reason,value)
                    reason = key[0]
                    totalValue+=key[1]
                    if reason in reasonDict:
                        reasonDict[reason]+=1
                    else:
                        reasonDict[reason]=1
                if self.verbose:
                    subredditname = unicodedata.normalize('NFKD', comment.subreddit.display_name).encode('ascii','ignore')
                    print("[*] Found potentially racist comment: "+comment.id+" in /r/"+subredditname)
                    print("[*] Value: "+str(totalValue))
                # Make sentence based on racism
                for racismReason, count in reasonDict.iteritems():
                    replyText+=racismReason+"("+str(count)+"), "
                # Just for crackers
                print(quotes)
                if "cracker" in quotes or "crackers" in quotes:
                    replyText = replyText[:-2]+", or references to [crackers](http://en.wikipedia.org/wiki/Cracker_\(food\)), "
                
                replyText = replyText[:-2]+"!  \n\n  "
                i=1
                for quote in quotes:
                    replyText+="\t"+str(i)+". "+quote+"\n\n"
                    i+=1
                if self.verbose:
                    for racismReason, count in reasonDict.iteritems():
                        print("\t-"+racismReason)
                if self.verbose:
                    commentBody = unicodedata.normalize('NFKD', comment.body.strip()).encode('ascii','ignore')
                    print("[*] "+commentBody)
                    print("[*] Reply:\n"+replyText)
                # Try to reply
                if addTODO:
                    if self.verbose:print("[*] Adding comment to todo stack")
                    self.todo.add((comment,replyText),totalValue)
                    self.todoIDs.append(comment.id)
                else:
                    try:
                        if self.reply:
                            comment.reply(replyText)
                            if self.verbose:print("\t[+] Replied: "+replyText)
                        else:
                            if self.verbose:print("\t[+] Would reply:\n\t"+replyText)
                        self.alreadyDone.add(comment.id)
                    except praw.errors.RateLimitExceeded as e:
                        if self.verbose:
                            print("\t[!] Cannot reply: Ratelimit Error")
                            print("\t[*] "+e.message)
                            print("\t[*] Adding comment to TODO set")
                            self.todo.add((comment,replyText),totalValue)
                            self.todoIDs.append(comment.id)
                    
    def checkIfCommentIsRacist(self,commentText):
        '''
        Checks if a comment(string) is racist, returns (boolean,List)
        '''
        originalCommentText = commentText.lower()
        racistCommentList = []
        for racistComment in self.racismKeyPhrases:
            commentText = originalCommentText
            while True:
                racistLocation = commentText.find(racistComment.lower())
                if racistLocation>-1: #additional tests
                    passedTests = False
                    # If at beginning
                    if racistLocation==0:
                        # If the racist comment is at the end OR immediately followed by <space/newline>
                        if len(commentText)==racistLocation+len(racistComment):
                            passedTests = True
                        else:
                            selChar = commentText[len(racistComment)]
                            if selChar.isspace() or (selChar in string.punctuation):
                                passedTests = True
                    # Else if at end
                    elif racistLocation+len(racistComment)==len(commentText):
                        # if the char before is <space/newline>
                        selChar = commentText[racistLocation-1]
                        if selChar.isspace() or (selChar in string.punctuation):
                            passedTests = True
                    # Else in the middle
                    else:
                        selChar1 = commentText[racistLocation-1]
                        selChar2 = commentText[racistLocation+len(racistComment)]
                        if selChar1.isspace() and (selChar2.isspace() or (selChar2 in string.punctuation)):
                            passedTests = True
                    if passedTests:
                        racistCommentList.append(racistComment)
                    commentText = commentText.replace(racistComment.lower(),"",1)
                else:
                    break
        if len(racistCommentList)>0:
            return (True,racistCommentList)
        return (False,None)