python-irclibを使ってIRCのBotを作成する
というわけでIRC BotをPythonを使って、書いてみる。
細かい作業やらせようとすると色々と面倒になるけど、
簡単な振る舞いの実装までてけてけ書いて行こうと思う。
環境
$ uname -a Linux hoge 2.6.32-358.23.2.el6.x86_64 #1 SMP Wed Oct 16 18:37:12 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux $ python -V Python 2.6.6
インストール
PyPIにパッケージとして登録されてるけど、pipでインストールしようとすると上手くいかない。
easy_installも同様、上手くいかない
$ pip search irclib python-irclib - IRC client library irclib - Douglbutt - Simple, extensible irclib based IRC bot. $ pip install python-irclib Downloading/unpacking python-irclib Could not find any downloads that satisfy the requirement python-irclib Cleaning up... No distributions at all found for python-irclib Storing complete log in /home/tututen/.pip/pip.log $ pip install irclib Downloading/unpacking irclib Could not find any downloads that satisfy the requirement irclib Cleaning up... No distributions at all found for irclib Storing complete log in /home/tututen/.pip/pip.log $ easy_install irclib Searching for python-irclib Reading https://pypi.python.org/simple/python-irclib/ Reading http://python-irclib.sourceforge.net Reading http://sourceforge.net/project/showfiles.php?group_id=38297 Best match: python-irclib 0.6.4 Downloading http://sourceforge.net/projects/python-irclib/files/python-irclib-0.6.4.zip/download Processing python-irclib-0.6.4.zip Writing /tmp/easy_install-fADYl5/python-irclib-0.6.4/setup.cfg Running python-irclib-0.6.4/setup.py -q bdist_egg --dist-dir /tmp/easy_install-fADYl5/python-irclib-0.6.4/egg-dist-tmp-KP109_ error: paver-minilib.zip: No such file or directory
諦めて、sourceforgeのWebサイトの方へ行くと、
MercurialのリポジトリがBitbucketにあるっぽい、けど作者さんのリポじゃないっぽい。
まぁ、SourceForgeから落としてきます
ちなみに
PyPI: python-irclib 0.4.8 : Python Package Index
SourceForge: Python IRC client library - Browse Files at SourceForge.net
# 現時点 0.6.4が最新版 $ wget http://downloads.sourceforge.net/project/python-irclib/python-irclib-0.6.4.zip $ unzip python-irclib-0.6.4.zip Archive: python-irclib-0.6.4.zip inflating: python-irclib-0.6.4/.cvsignore inflating: python-irclib-0.6.4/.hgignore inflating: python-irclib-0.6.4/.hgtags inflating: python-irclib-0.6.4/ChangeLog inflating: python-irclib-0.6.4/CHANGES inflating: python-irclib-0.6.4/COPYING inflating: python-irclib-0.6.4/MANIFEST.in inflating: python-irclib-0.6.4/pavement.py inflating: python-irclib-0.6.4/paver-minilib.zip inflating: python-irclib-0.6.4/PKG-INFO inflating: python-irclib-0.6.4/README inflating: python-irclib-0.6.4/setup.cfg inflating: python-irclib-0.6.4/setup.py inflating: python-irclib-0.6.4/lib/ircbot.py inflating: python-irclib-0.6.4/lib/irclib.py inflating: python-irclib-0.6.4/lib/python_irclib.egg-info/dependency_links.txt inflating: python-irclib-0.6.4/lib/python_irclib.egg-info/PKG-INFO inflating: python-irclib-0.6.4/lib/python_irclib.egg-info/SOURCES.txt inflating: python-irclib-0.6.4/lib/python_irclib.egg-info/top_level.txt inflating: python-irclib-0.6.4/scripts/dccreceive inflating: python-irclib-0.6.4/scripts/dccsend inflating: python-irclib-0.6.4/scripts/irccat inflating: python-irclib-0.6.4/scripts/irccat2 inflating: python-irclib-0.6.4/scripts/servermap inflating: python-irclib-0.6.4/scripts/testbot.py inflating: python-irclib-0.6.4/tests/test_ircbot.py inflating: python-irclib-0.6.4/tests/test_irclib.py inflating: python-irclib-0.6.4/tests/__init__.py $ cd python-irclib-0.6.4 $ python setup.py Searching for hgtools Reading https://pypi.python.org/simple/hgtools/ Best match: hgtools 4.0 Downloading https://pypi.python.org/packages/source/h/hgtools/hgtools-4.0.zip#md5=a1b58801ec06de50ce4247f66c28e9cd Processing hgtools-4.0.zip Writing /tmp/easy_install-VR6nzx/hgtools-4.0/setup.cfg Running hgtools-4.0/setup.py -q bdist_egg --dist-dir /tmp/easy_install-VR6nzx/hgtools-4.0/egg-dist-tmp-kuajse Traceback (most recent call last): File "setup.py", line 10, in <module> paver.tasks.main() File "paver-minilib.zip/paver/tasks.py", line 808, in main File "paver-minilib.zip/paver/tasks.py", line 786, in _launch_pavement File "paver-minilib.zip/paver/tasks.py", line 746, in _process_commands File "paver-minilib.zip/paver/tasks.py", line 107, in get_task File "paver-minilib.zip/paver/setuputils.py", line 167, in get_task File "paver-minilib.zip/paver/setuputils.py", line 195, in _get_distribution File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/setuptools/dist.py", line 265, in __init__ self.fetch_build_eggs(attrs.pop('setup_requires')) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/setuptools/dist.py", line 289, in fetch_build_eggs parse_requirements(requires), installer=self.fetch_build_egg File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/pkg_resources.py", line 618, in resolve dist = best[req.key] = env.best_match(req, self, installer) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/pkg_resources.py", line 862, in best_match return self.obtain(req, installer) # try and download/install File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/pkg_resources.py", line 874, in obtain return installer(requirement) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/setuptools/dist.py", line 339, in fetch_build_egg return cmd.easy_install(req) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/setuptools/command/easy_install.py", line 623, in easy_install return self.install_item(spec, dist.location, tmpdir, deps) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/setuptools/command/easy_install.py", line 653, in install_item dists = self.install_eggs(spec, download, tmpdir) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/setuptools/command/easy_install.py", line 849, in install_eggs return self.build_and_install(setup_script, setup_base) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/setuptools/command/easy_install.py", line 1130, in build_and_install self.run_setup(setup_script, setup_base, args) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/setuptools/command/easy_install.py", line 1115, in run_setup run_setup(setup_script, args) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/setuptools/sandbox.py", line 66, in run_setup working_set.__init__() File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/pkg_resources.py", line 476, in __init__ self.add_entry(entry) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/pkg_resources.py", line 491, in add_entry for dist in find_distributions(entry, True): File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/pkg_resources.py", line 1963, in find_in_zip metadata = EggMetadata(importer) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/pkg_resources.py", line 1852, in __init__ self.zipinfo = build_zipmanifest(importer.archive) File "/home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/pkg_resources.py", line 1583, in build_zipmanifest zfile = zipfile.ZipFile(path) File "/usr/lib64/python2.6/zipfile.py", line 683, in __init__ self.fp = open(file, modeDict[mode]) IOError: [Errno 2] No such file or directory: 'paver-minilib.zip'
なんか「paver-minilib.zip」なんてねぇよ!ッて言われてます。
でも「python-irclib.0.6.4」の中にちゃんと含まれてます。
そこで絶対パスの指定に変更しちゃいます。
- setup.py
try: import paver.tasks except ImportError: import os if os.path.exists("paver-minilib.zip"): import sys sys.path.insert(0, "paver-minilib.zip") import paver.tasks paver.tasks.main()
の中身の
sys.path.insert(0, "paver-minilib.zip")
を、os.path.abspathを使って
sys.path.insert(0, os.path.abspath("paver-minilib.zip"))
に変更して実行すると、
$ python setup.py Searching for hgtools Reading https://pypi.python.org/simple/hgtools/ Best match: hgtools 4.0 Downloading https://pypi.python.org/packages/source/h/hgtools/hgtools-4.0.zip#md5=a1b58801ec06de50ce4247f66c28e9cd Processing hgtools-4.0.zip Writing /tmp/easy_install-xMEenz/hgtools-4.0/setup.cfg Running hgtools-4.0/setup.py -q bdist_egg --dist-dir /tmp/easy_install-xMEenz/hgtools-4.0/egg-dist-tmp-mIOSpg running bdist_egg running egg_info writing hgtools.egg-info/PKG-INFO writing top-level names to hgtools.egg-info/top_level.txt writing dependency_links to hgtools.egg-info/dependency_links.txt writing entry points to hgtools.egg-info/entry_points.txt writing hgtools.egg-info/PKG-INFO writing top-level names to hgtools.egg-info/top_level.txt writing dependency_links to hgtools.egg-info/dependency_links.txt writing entry points to hgtools.egg-info/entry_points.txt reading manifest file 'hgtools.egg-info/SOURCES.txt' writing manifest file 'hgtools.egg-info/SOURCES.txt' installing library code to build/bdist.linux-x86_64/egg running install_lib running build_py creating build creating build/lib creating build/lib/hgtools copying hgtools/versioning.py -> build/lib/hgtools copying hgtools/__init__.py -> build/lib/hgtools copying hgtools/plugins.py -> build/lib/hgtools creating build/lib/hgtools/tests copying hgtools/tests/test_managers.py -> build/lib/hgtools/tests copying hgtools/tests/test_versioning.py -> build/lib/hgtools/tests copying hgtools/tests/__init__.py -> build/lib/hgtools/tests copying hgtools/tests/test_reentry.py -> build/lib/hgtools/tests creating build/lib/hgtools/managers copying hgtools/managers/subprocess.py -> build/lib/hgtools/managers copying hgtools/managers/reentry.py -> build/lib/hgtools/managers copying hgtools/managers/__init__.py -> build/lib/hgtools/managers copying hgtools/managers/library.py -> build/lib/hgtools/managers copying hgtools/managers/base.py -> build/lib/hgtools/managers copying hgtools/managers/cmd.py -> build/lib/hgtools/managers creating build/bdist.linux-x86_64 creating build/bdist.linux-x86_64/egg creating build/bdist.linux-x86_64/egg/hgtools creating build/bdist.linux-x86_64/egg/hgtools/tests copying build/lib/hgtools/tests/test_managers.py -> build/bdist.linux-x86_64/egg/hgtools/tests copying build/lib/hgtools/tests/test_versioning.py -> build/bdist.linux-x86_64/egg/hgtools/tests copying build/lib/hgtools/tests/__init__.py -> build/bdist.linux-x86_64/egg/hgtools/tests copying build/lib/hgtools/tests/test_reentry.py -> build/bdist.linux-x86_64/egg/hgtools/tests copying build/lib/hgtools/versioning.py -> build/bdist.linux-x86_64/egg/hgtools creating build/bdist.linux-x86_64/egg/hgtools/managers copying build/lib/hgtools/managers/subprocess.py -> build/bdist.linux-x86_64/egg/hgtools/managers copying build/lib/hgtools/managers/reentry.py -> build/bdist.linux-x86_64/egg/hgtools/managers copying build/lib/hgtools/managers/__init__.py -> build/bdist.linux-x86_64/egg/hgtools/managers copying build/lib/hgtools/managers/library.py -> build/bdist.linux-x86_64/egg/hgtools/managers copying build/lib/hgtools/managers/base.py -> build/bdist.linux-x86_64/egg/hgtools/managers copying build/lib/hgtools/managers/cmd.py -> build/bdist.linux-x86_64/egg/hgtools/managers copying build/lib/hgtools/__init__.py -> build/bdist.linux-x86_64/egg/hgtools copying build/lib/hgtools/plugins.py -> build/bdist.linux-x86_64/egg/hgtools byte-compiling build/bdist.linux-x86_64/egg/hgtools/tests/test_managers.py to test_managers.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/tests/test_versioning.py to test_versioning.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/tests/__init__.py to __init__.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/tests/test_reentry.py to test_reentry.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/versioning.py to versioning.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/managers/subprocess.py to subprocess.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/managers/reentry.py to reentry.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/managers/__init__.py to __init__.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/managers/library.py to library.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/managers/base.py to base.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/managers/cmd.py to cmd.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/__init__.py to __init__.pyc byte-compiling build/bdist.linux-x86_64/egg/hgtools/plugins.py to plugins.pyc creating build/bdist.linux-x86_64/egg/EGG-INFO copying hgtools.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO copying hgtools.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO copying hgtools.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO copying hgtools.egg-info/entry_points.txt -> build/bdist.linux-x86_64/egg/EGG-INFO copying hgtools.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO zip_safe flag not set; analyzing archive contents... creating '/tmp/easy_install-xMEenz/hgtools-4.0/egg-dist-tmp-mIOSpg/hgtools-4.0-py2.6.egg' and adding 'build/bdist.linux-x86_64/egg' to it removing 'build/bdist.linux-x86_64/egg' (and everything under it) Moving hgtools-4.0-py2.6.egg to /home/tututen/work/ircbot/python-irclib-0.6.4 Installed /home/tututen/work/ircbot/python-irclib-0.6.4/hgtools-4.0-py2.6.egg
上手くBuild通ったので、インストールしちゃいましょう。
$ python setup.py install running install running build running build_py creating build creating build/lib copying lib/irclib.py -> build/lib copying lib/ircbot.py -> build/lib running install_lib copying build/lib/ircbot.py -> /home/tututen/_sandbox/ircbot/lib/python2.6/site-packages copying build/lib/irclib.py -> /home/tututen/_sandbox/ircbot/lib/python2.6/site-packages byte-compiling /home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/ircbot.py to ircbot.pyc byte-compiling /home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/irclib.py to irclib.pyc running install_egg_info running egg_info writing lib/python_irclib.egg-info/PKG-INFO writing top-level names to lib/python_irclib.egg-info/top_level.txt writing dependency_links to lib/python_irclib.egg-info/dependency_links.txt reading manifest file 'lib/python_irclib.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' writing manifest file 'lib/python_irclib.egg-info/SOURCES.txt' Copying lib/python_irclib.egg-info to /home/tututen/_sandbox/ircbot/lib/python2.6/site-packages/python_irclib-0.6.4-py2.6.egg-info running install_scripts
上手く出来たっぽいです。
確認の為にimportしてみましょう。
$ python Python 2.6.6 (r266:84292, Nov 22 2013, 12:16:22) [GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import irclib >>>
大丈夫そうですね。
サンプル
動作確認まで行けたのでコードを書いて行きます。
ちょっと長いですが、最低限の機能ですので。
- bot.py
# coding: utf-8 from irclib import nm_to_n, nm_to_h from ircbot import SingleServerIRCBot IRC_SERVER = 'irc.ircnet.ne.jp' IRC_PORT = 6667 IRC_PASS = '' IRC_NICK = 'test_bot' CHANNEL = '#tututen_my' ENCODING = 'iso-2022-jp' class IRCBot(SingleServerIRCBot): def __init__(self): print 'init' if IRC_PASS: SingleServerIRCBot.__init__(self, [(IRC_SERVER, IRC_PORT, IRC_PASS)], IRC_NICK, IRC_NICK) else: SingleServerIRCBot.__init__(self, [(IRC_SERVER, IRC_PORT)], IRC_NICK, IRC_NICK) def say(self, irc, msg): u""" 文字コードの変換をして発言する """ if type(msg) != 'unicode': msg = unicode(msg) irc.privmsg(CHANNEL, msg.encode(ENCODING, 'replace')) def on_nicknameinuse(self, irc, e): u""" BOTの名前がかぶったら名前変えるよ """ print 'on_nicknameinuse' irc.nick(irc.get_nickname() + '_') def on_welcome(self, irc, e): u""" IRCサーバ接続時の処理するよ """ print 'on_welcome' # チャンネルに入る+挨拶 irc.join(CHANNEL) self.say(irc, u'こんにちは') def on_join(self, irc, e): u""" 誰かがチャンネルに繋いだ時に処理するよ(自分含) """ print 'on_join' # 接続した名前 nick = nm_to_n(e.source()) if nick == irc.get_nickname(): return # 今繋いでるチャンネルの情報を取得する ch = self.channels[e.target()] # Botになるとあったら繋いだ人になると上げるよ if ch.is_oper(irc.ircname): irc.mode(e.target(), '+o %s' % nick) def on_privmsg(self, irc, e): u""" 誰かが発言した時に処理するよ """ print 'on_privmsg' nick, host, msg = '', '', '' try: nick = nm_to_n(e.source()) host = nm_to_h(e.source()) msg = unicode(e.arguments()[0], ENCODING) except Exception, e: print str(e) return if msg[0] == ':': command = msg[1:] # :omikuji って発言すると占ってくれるよ if command == 'omikuji': omikuji_list = [u'大吉', u'中吉', u'吉', u'凶'] import random omikuji_msg = u'%s さんの運勢は %sです' % \ (nick, random.choice(omikuji_list)) self.say(irc, omikuji_msg) # pubmsgでも反応するようにする on_pubmsg = on_privmsg if __name__ == '__main__': IRCBot().start()
起動方法
$ python bot.py