読者です 読者をやめる 読者になる 読者になる

Python で実装する IRCボット

たまたま作る機会があった IRCボットを Python で実装してみたメモ。

環境は CentOS 5.4、Python 2.4

python-irclib

IRCボットを簡単に作成できるライブラリ、python-irclib をインストールする。

  
$ wget http://sourceforge.net/projects/python-irclib/files/python-irclib/0.4.8/python-irclib-0.4.8.zip/download  
$ unzip python-irclib-0.4.8.zip  
$ cd python-irclib-0.4.8  
$ python setup.py build  
$ sudo python setup.py install  

ソースコード

下のコードは、ある時間になったら挨拶するボットのサンプルコード。

  
#!/usr/bin/env python  
# -*- coding: utf-8 -*-  
  
from ircbot import SingleServerIRCBot  
from irclib import nm_to_n  
import datetime  
  
IRC_SERVER = "192.168.11.30"  
IRC_PORT = 6667  
IRC_CHANNEL = "#HOGE"  
IRC_NICK = "botpy"  
IRC_TIMER_SEC = 60  
  
class BotPy(SingleServerIRCBot):  
    """  
    bot class  
    """  
      
    def __init__(self):  
        """  
        コネクションを張る  
        """  
        SingleServerIRCBot.__init__(self, [(IRC_SERVER, IRC_PORT)], IRC_NICK, IRC_NICK)  
        self.channel = IRC_CHANNEL  
      
    def on_nicknameinuse(self, c, e):  
        """  
        ニックネームが被ってたら末尾に _ を付ける  
        """  
        c.nick( c.get_nickname() + "_" )  
      
    def on_welcome(self, c, e):  
        """  
        サーバに接続成功。指定チャンネルに入る  
        """  
        print "welcome"  
        c.join( self.channel )  
          
    def on_privmsg(self, c, e):  
        """  
        メッセージを検知  
        """  
        try:  
            nick = nm_to_n( e.source() )  
            msg = unicode( e.arguments()[0], "iso-2022-jp" ).encode("utf-8")  
        except:  
            print str(e)  
            return  
        print "%s: %s" % (nick, msg)  
          
    on_pubmsg = on_privmsg  
      
    def on_ping(self, c, e):  
        self.connection.pong( self.channel )  
  
    def privmsg(self, str):  
        """  
        チャット発言  
        """  
        self.connection.privmsg( self.channel, unicode(str, "utf8").encode("iso-2022-jp", "ignore") )  
      
    def notice(self, str):  
        """  
        通知発言  
        """  
        self.connection.notice( self.channel, unicode(str, "utf8").encode("iso-2022-jp", "ignore") )  
          
    def add_execute_delayed(self, sec, callback, obj):  
        """  
        遅延実行関数(指定秒たったら、指定関数を実行)  
        """  
        self.ircobj.execute_delayed(sec, callback, obj)  
  
def call_timer( bot ):  
    """  
    タイマー関数  
    9時と12時と19時に挨拶する  
    指定秒間隔でポーリング  
    """  
    d = datetime.datetime.today()  
    # 時報  
    if( d.hour == 9 and d.minute == 0 ):  
        bot.notice( "おはようございます" )  
    elif( d.hour == 12 and d.minute == 0 ):  
        bot.notice( "こんにちわ" )  
    elif( d.hour == 19 and d.minute == 0 ):  
        bot.notice( "こんばんわ" )  
    bot.add_execute_delayed( IRC_TIMER_SEC, call_timer, (bot,))  
  
bot = BotPy()  
bot.add_execute_delayed( IRC_TIMER_SEC, call_timer, (bot,))  
bot.start()  

↑のコードを書いてるときに一番悩んだのが、タイマー的な処理の仕方。

結局、BotPy::add_execute_delayed()で呼び出しているself.ircobj.execute_delayed()を使って、解決した。

このメソッドは irclib::IRC クラスのメソッドで、
第一引数が秒数、第二引数がコールバック関数、第三引数がコールバック関数に渡す引数になっている。

「第二引数に設定した関数」を「第一引数に設定した秒数」ごとに呼び出してくれる素敵メソッドだ。
登録したコールバック関数は、内部で勝手に始末してくれるのでリーク的な心配もない。

文字コード周りが、地味に面倒だったず。