Recipe 13.16. Connecting to IRC and Logging Messages to DiskCredit: Gian Mario Tagliaretti, J P Calderone ProblemYou want to connect to an IRC (Internet Relay Chat) server, join a channel, and store private messages into a file on your hard disk for future reading. SolutionThe Twisted framework has excellent support for many network protocols, including IRC, so we can perform this recipe's task with a very simple script: from twisted.internet import reactor, protocol from twisted.protocols import irc class LoggingIRCClient(irc.IRCClient): logfile = file('/tmp/msg.txt', 'a+') nickname = 'logging_bot' def signedOn(self): self.join('#test_py') def privmsg(self, user, channel, message): self.logfile.write(user.split('!')[0] + ' -> ' + message + '\n') self.logfile.flush( ) def main( ): f = protocol.ReconnectingClientFactory( ) f.protocol = LoggingIRCClient reactor.connectTCP('irc.freenode.net', 6667, f) reactor.run( ) if _ _name_ _ == '_ _main_ _': main( ) DiscussionIf, for some strange reason, you cannot use Twisted, then you can implement similar functionality from scratch based only on the Python Standard Library. Here's a reasonable approachnowhere as simple, solid, and robust as, and lacking the beneficial performance of, Twisted, but nevertheless sort of workable: import socket SERVER = 'irc.freenode.net' PORT = 6667 NICKNAME = 'logging_bot' CHANNEL = '#test_py' IRC = socket.socket(socket.AF_INET, socket.SOCK_STREAM) def irc_conn( ): IRC.connect((SERVER, PORT)) def send_data(command): IRC.send(command + '\n') def join(channel): send_data("JOIN %s" % channel) def login(nickname, username='user', password=None, realname='Pythonist', hostname='Helena', servername='Server'): send_data("USER %s %s %s %s" % (username, hostname, servername, realname)) send_data("NICK %s" % nickname) irc_conn( ) login(NICKNAME) join(CHANNEL) filetxt = open('/tmp/msg.txt', 'a+') try: while True: buffer = IRC.recv(1024) msg = buffer.split( ) if msg[0] == "PING": # answer PING with PONG, as RFC 1459 specifies send_data("PONG %s" % msg[1]) if msg [1] == 'PRIVMSG' and msg[2] == NICKNAME: nick_name = msg[0][:msg[0].find("!")] message = ' '.join(msg[3:]) filetxt.write(nick_name.lstrip(':') + ' -> ' + message.lstrip(':') + '\n') filetxt.flush( ) finally: filetxt.close( ) For this roll-our-own reimplementation, we do need some understanding of the protocol's RFC, such as the need to answer a server's PING with a proper PONG to confirm that our connection is alive. In any case, since the code has already grown to over twice as much as Twisted requires, we've omitted niceties (which are very important for reliable unattended operation) such as automatic reconnection attempts when the connection drops, which Twisted gives us effortlessly via its protocol.ReconnectingClientFactory. See AlsoDocumentation for the standard library module socket in the Library Reference and Python in a Nutshell; twisted is at http://www.twistedmatrix.com. |