Recipe 13.16. Connecting to IRC and Logging Messages to Disk
Credit: Gian Mario Tagliaretti, J P Calderone
Problem
You 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.
Solution
The 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( )
Discussion
If, 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 socketFor this roll-our-own reimplementation, we do need some understanding
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( )
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 Also
Documentation for the standard library module
socket in the Library
Reference and Python in a
Nutshell; twisted is at http://www.twistedmatrix.com.