2015-01-08 39 views
2

我將從我不是一個Python程序員開始......我已經修改了我的IRC頻道的扭曲機器人。我現在正在嘗試整合第二個線程,以便每隔30分鐘就可以在通道上獲取twitter更新,而不會中斷正常的IRC命令。如何正確添加第二個線程到Python機器人

我已經測試了twitter本身的更新代碼,它工作正常......但我不知道如何將它添加到機器人中的類和函數中,並使用twisted框架來發送消息。

這是Twitter更新所述碼塊:

# For Twitter feed 
from twitter import * 
from thread import start_new_thread 
from datetime import datetime, timedelta 
from twitter_app_credentials import * 
twitter = Twitter(
auth=OAuth(access_token_key, access_token_secret, consumer_key, consumer_secret)) 

def twitterthread(self, channel): 
    userlist = ['victorbrca', 'MississaugaLUG'] 
    keepthread = 1 
    while keepthread > 0: 
     for user in userlist: 
      raw = twitter.statuses.user_timeline(screen_name=user,count=1)[0] 
      create_date = raw['created_at'].encode('utf-8') 
      date = re.sub(r'\+[0-9]{4}', 'UTC', create_date) 
      cdate = datetime.strptime(date, '%a %b %d %H:%M:%S %Z %Y') 
      current_time = datetime.now() - timedelta(minutes = 30) 
      if cdate > current_time: 
       tweet = ("@%s: %s" % (raw["user"]["screen_name"], raw["text"])) 
       print tweet 
       time.sleep(10) 
      else: 
       print "no new tweets" 
      time.sleep(10) 

我想要麼經由命令時,或者當機器人加入信道,但不具有在同一時間運行的多個線程來啓動此。

這裏的最後一次提交什麼的機器人看起來就像一個(我試圖得到它的工作) - Commit

而這裏的默認扭曲機器人的樣子:

# Copyright (c) 2001-2009 Twisted Matrix Laboratories. 
# See LICENSE for details. 


""" 
An example IRC log bot - logs a channel's events to a file. 

If someone says the bot's name in the channel followed by a ':', 
e.g. 

    <foo> logbot: hello! 

the bot will reply: 

    <logbot> foo: I am a log bot 

Run this script with two arguments, the channel name the bot should 
connect to, and file to log to, e.g.: 

    $ python ircLogBot.py test test.log 

will log channel #test to the file 'test.log'. 
""" 


# twisted imports 
from twisted.words.protocols import irc 
from twisted.internet import reactor, protocol 
from twisted.python import log 

# system imports 
import time, sys 


class MessageLogger: 
    """ 
    An independent logger class (because separation of application 
    and protocol logic is a good thing). 
    """ 
    def __init__(self, file): 
     self.file = file 

    def log(self, message): 
     """Write a message to the file.""" 
     timestamp = time.strftime("[%H:%M:%S]", time.localtime(time.time())) 
     self.file.write('%s %s\n' % (timestamp, message)) 
     self.file.flush() 

    def close(self): 
     self.file.close() 


class LogBot(irc.IRCClient): 
    """A logging IRC bot.""" 

    nickname = "twistedbot" 

    def connectionMade(self): 
     irc.IRCClient.connectionMade(self) 
     self.logger = MessageLogger(open(self.factory.filename, "a")) 
     self.logger.log("[connected at %s]" % 
         time.asctime(time.localtime(time.time()))) 

    def connectionLost(self, reason): 
     irc.IRCClient.connectionLost(self, reason) 
     self.logger.log("[disconnected at %s]" % 
         time.asctime(time.localtime(time.time()))) 
     self.logger.close() 


    # callbacks for events 

    def signedOn(self): 
     """Called when bot has succesfully signed on to server.""" 
     self.join(self.factory.channel) 

    def joined(self, channel): 
     """This will get called when the bot joins the channel.""" 
     self.logger.log("[I have joined %s]" % channel) 

    def privmsg(self, user, channel, msg): 
     """This will get called when the bot receives a message.""" 
     user = user.split('!', 1)[0] 
     self.logger.log("<%s> %s" % (user, msg)) 

     # Check to see if they're sending me a private message 
     if channel == self.nickname: 
      msg = "It isn't nice to whisper! Play nice with the group." 
      self.msg(user, msg) 
      return 

     # Otherwise check to see if it is a message directed at me 
     if msg.startswith(self.nickname + ":"): 
      msg = "%s: I am a log bot" % user 
      self.msg(channel, msg) 
      self.logger.log("<%s> %s" % (self.nickname, msg)) 

    def action(self, user, channel, msg): 
     """This will get called when the bot sees someone do an action.""" 
     user = user.split('!', 1)[0] 
     self.logger.log("* %s %s" % (user, msg)) 

    # irc callbacks 

    def irc_NICK(self, prefix, params): 
     """Called when an IRC user changes their nickname.""" 
     old_nick = prefix.split('!')[0] 
     new_nick = params[0] 
     self.logger.log("%s is now known as %s" % (old_nick, new_nick)) 


    # For fun, override the method that determines how a nickname is changed on 
    # collisions. The default method appends an underscore. 
    def alterCollidedNick(self, nickname): 
     """ 
     Generate an altered version of a nickname that caused a collision in an 
     effort to create an unused related name for subsequent registration. 
     """ 
     return nickname + '^' 



class LogBotFactory(protocol.ClientFactory): 
    """A factory for LogBots. 

    A new protocol instance will be created each time we connect to the server. 
    """ 

    # the class of the protocol to build when new connection is made 
    protocol = LogBot 

    def __init__(self, channel, filename): 
     self.channel = channel 
     self.filename = filename 

    def clientConnectionLost(self, connector, reason): 
     """If we get disconnected, reconnect to server.""" 
     connector.connect() 

    def clientConnectionFailed(self, connector, reason): 
     print "connection failed:", reason 
     reactor.stop() 


if __name__ == '__main__': 
    # initialize logging 
    log.startLogging(sys.stdout) 

    # create factory protocol and application 
    f = LogBotFactory(sys.argv[1], sys.argv[2]) 

    # connect factory to this host and port 
    reactor.connectTCP("irc.freenode.net", 6667, f) 

    # run bot 
    reactor.run() 

感謝。

回答

0

請勿使用線程。使用https://github.com/dustin/twitty-twistertwisted.internet.task.LoopingCall

+1

不,你錯過了Twisted的要點。 –

+0

我真的沒有看到轉變爲twitty的一點,因爲我已經有Twitter API的工作。但是使用Twisted的LoopingCall確實讓我朝着正確的方向發展。 – victorbrca

+1

共享狀態線程本身就很複雜,並且會使您的程序無法診斷錯誤。避免使用非阻塞Twitter API集成的線程將允許您的程序對來自IRC連接和Twitter請求的響應做出反應,而不會阻礙另一個阻止。 – Glyph

0

我想通過Jean-Paul與LoopingCall一起工作的想法,找到了我需要的方法。

我定義了檢查Twitter的更新功能:

def twitterFeed(self, channel): 
     twitter_userlist = ['victorbrca', 'MississaugaLUG'] 
     for user in twitter_userlist: 
      RawTweet = twitter.statuses.user_timeline(screen_name=user,count=1)[0] 
      RawTweetDate = RawTweet['created_at'] 
      UTCRawTweetDate = re.sub(r'\+[0-9]{4}', 'UTC', RawTweetDate) 
      TweetDateToTime = datetime.strptime(UTCRawTweetDate, '%a %b %d %H:%M:%S %Z %Y') 
      TweetDate = TweetDateToTime.strftime('%Y-%b-%d %H:%M') 
      GetFiveMinAgo = datetime.utcnow() - timedelta(minutes = 5) 
      FiveMinAgo = GetFiveMinAgo.strftime('%Y-%b-%d %H:%M') 
      if FiveMinAgo < TweetDate: 
       CurrentTime = datetime.utcnow() 
       diff = relativedelta(CurrentTime, TweetDateToTime) 
       if diff.minutes < 1: 
        Ago = "%s seconds ago" % diff.seconds 
       else: 
        Ago = "%s minutes ago" % diff.minutes 
       tweet = ("@%s: %s (%s)" % (RawTweet["user"]["screen_name"], RawTweet["text"], Ago)) 
       msg = tweet.encode('utf-8') 
       self.sendLine("PRIVMSG %s :%s" % (channel, msg)) 

和函數被調用的命令通過LoopingCall(現在):

# Start Twitter feed 
elif msg == "!starttwitter" and user == authorized_user: 
    task = LoopingCall(self.twitterFeed, channel) 
    task.start(300) 

感謝所有的答覆。

+1

更改爲非阻塞Twitter客戶端的目的是爲了避免阻塞阻止API調用Twitter的反應器事件循環。 –

+0

使用像這樣的阻止twitter客戶端的問題是,如果twitter API速度變慢並導致程序暫停,整個程序將停止並等待;如果您的IRC連接停止並等待這個原因太久,您將會被踢出IRC。由於twitter API的性能變化很大,並且您的網絡速度可能很慢,所以這是非常現實的可能性。 – Glyph

+0

感謝您的解釋傢伙。我提到的一個重要因素是我不是Python程序員。我花了2個多小時纔開始Twitter API工作......所以不得不重新寫入另一個客戶端,這是一個我還沒有準備好的旅程。但是我會記住這一點,因爲我提高了自己的技能,因此我必須考慮這個機器人。 – victorbrca

相關問題