Gå til innhold

Anbefalte innlegg

Jeg er helt fersk på pyton, kommer fra en verden av php... Men jeg digger python allerde (Tving meg ikke til å satse på noe annet..) :D

 

Jeg får til å koble meg på "irc.freenode.net", men målet er å få den inn på "irc.quakenet.org", noe som viste seg vanskeligere.. Det krever at jeg svarer på en PING, med en random string bak. Hvor jeg da skal svare noe ala:

 

def ping(): # This is our first function! It will respond to server Pings.
 ircsock.send("/QUOTE PONG "+ pingrespons +"\n") 

 #hvordan lage respons med random nummeret som kommer?

PING: 1163268885 #tallet er en random string som jeg får (må snappes opp og returneres)..

 

import socket 

server = "irc.freenode.net" # Server
channel = "#slacky" # Channel
botnick = "slacky" # Your bots nick
port = 6667


def ping(): # This is our first function! It will respond to server Pings.
 #ircsock.send("/QUOTE PONG"+ HVORDAN +"\n") 
 ircsock.send("PONG :pingis\n")  

def sendmsg(chan , msg): # This is the send message function, it simply sends messages to the channel.
 ircsock.send("PRIVMSG "+ chan +" :"+ msg +"\n") 

def joinchan(chan): # This function is used to join channels.
 ircsock.send("JOIN "+ chan +"\n")

def beer():
 ircsock.send("PRIVMSG "+ channel +" :I would like som beer now!\n")

ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ircsock.connect((server, port)) # Here we connect to the server using the port 6667
ircsock.send("USER "+ botnick +" "+ botnick +" "+ botnick +" :slackbot.\n") # user authentication
ircsock.send("NICK "+ botnick +"\n") # here we actually assign the nick to the bot

joinchan(channel) # Join the channel using the functions we previously defined

while 1: # Be careful with these! it might send you to an infinite loop
 ircmsg = ircsock.recv(2048) # receive data from the server
 ircmsg = ircmsg.strip('\n\r') # removing any unnecessary linebreaks.
 print(ircmsg) # Here we print what's coming from the server

 if ircmsg.find(":beer") != -1:
   beer()

 if ircmsg.find("PING :") != -1: # if the server pings us then we've got to respond!
   ping()

 

http://img828.imageshack.us/img828/2280/pingpongh.jpg

Endret av tROOP4H
Lenke til kommentar
Videoannonse
Annonse

Et lite tips er å skrive ting objektorientert, selv om du er i starten av å lære ting. Spesielt i Python er det å kunne OOP godt en veldig god egenskap.

 

Når det kommer til IRC protokollen husk følgende:

- Alle argumenter deles opp med mellomrom, ikke etter ":"

- PING skal svares med PONG {alt bak}

----- Feks. "PING :1234" svares med "PONG :1234"

- Du kan ikke vite at du er connected til en server før du får welcome message fra serveren (kode "001")

 

Det du ønsker å gjøre er noe følgende:

cmdParts = msg.split(' ')
if cmdParts[0] == 'PING':
   self.sendCmd("PONG %s" % cmdParts[1])

 

Skrev et objektorientert eksempel du kan se på om du ønsker, basert på din kode og som bruker file-sockets. (slik at du kan lese fra sockets som om de var filer). Denne kan fint connecte til f.eks. quakenet.

import socket 

server = "irc.quakenet.org" # Server
channel = "#slacky" # Channel
botnick = "slacky" # Your bots nick
port = 6667


class IrcBot:
   def __init__(self, server, port, channel, nick):
       # Save some variables for later
       self.connected = False
       self.channel = channel
       self.host = server

       # Setup the socket, fsock is a python-implementation to let you read
       # from TCP as if it was a normal file.
       self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
       self.fsock = self.socket.makefile()

       # Connect to server
       print "Connecting to %s:%d" % (server, port)
       self.socket.connect((server, port))
       self.sendCmd("USER %s 0 * :%s" % (nick, nick))
       self.sendCmd("NICK "+ botnick)

       # Run it
       self._run()

   # Just to make code easier to read
   def sendCmd(self, cmd):
       print "<<<", cmd
       self.fsock.write(cmd + "\r\n")
       self.fsock.flush()

   # Send a message to a channel
   def sendmsg(self, chan , msg):
       self.sendCmd("PRIVMSG "+ chan +" :"+ msg) 

   # Join a channel
   def joinChan(self, chan): # This function is used to join channels.
       self.sendCmd("JOIN " + chan)

   # This is the main-loop of the IrcBot. Reads info from TCP
   def _run(self):
       while 1:
           msg = self.fsock.readline()
           if msg is "": # If we get a blank line, no new message recieved
               continue
           msg = msg.rstrip()
           print ">>>", msg
           self.parse(msg)

   # Parses a line, and handles it correctly
   def parse(self, msg):
       cmdParts = msg.split(' ')
       if cmdParts[0] == 'PING':
           self.sendCmd("PONG %s" % cmdParts[1])

       elif msg[0] == ':': # A server msg
           if cmdParts[1] == '001': # The welcome message, we are now connected
               self.connected = True
               self.joinChan(self.channel)

if __name__ == '__main__':
   bot = IrcBot(server, port, channel, botnick)

Endret av etse
  • Liker 1
Lenke til kommentar

Ser man det ja! Dette likte jeg virkelig! :)

 

Vel, jeg ser ikke helt hvordan jeg skal lage en slik "beer"-respons, som jeg hadde i tidligere.. Der skrev jeg simpelthen "beer" på IRC og den svarte et eller annet tilbake..

 

 

EDIT: Nesten fikset :S

 

...
   # Parses a line, and handles it correctly
   def parse(self, msg):
       cmdParts = msg.split(' ')
       if cmdParts[0] == 'PING':
           self.sendCmd("PONG %s" % cmdParts[1])

       elif msg[0] == ':': # A server msg
           if cmdParts[1] == '001': # The welcome message, we are now connected
               self.connected = True
               self.joinChan(self.channel)

def beer():
	self.sendCmd("PRIVMSG "+ channel +" :I would like som beer now!\n")

if msg.find(":beer") != -1: # Oh noes! I must respond!!
	beer()

if __name__ == '__main__':
   bot = IrcBot(server, port, channel, botnick)

 

Men da fikk jeg problmet: Legger jeg til flere kommandoer krasher botten, og ga meg "Quit (Read error: EOF from client)"

Endret av tROOP4H
Lenke til kommentar

om du ser i mitt eksempel har jeg en metode i klassen min som heter "parse". Denne brukes til å behandle ulike tilfeller.

    # Parses a line, and handles it correctly
   def parse(self, msg):
       cmdParts = msg.split(' ')
       if cmdParts[0] == 'PING':
           self.sendCmd("PONG %s" % cmdParts[1])

       elif msg[0] == ':': # A server msg
           if cmdParts[1] == '001': # The welcome message, we are now connected
               self.connected = True
               self.joinChan(self.channel)

 

Vi tar å legger til håndtering for privmsg.:

om du ser i mitt eksempel har jeg en metode i klassen min som heter "parse". Denne brukes til å behandle ulike tilfeller.

    # Parses a line, and handles it correctly
   def parse(self, msg):
       cmdParts = msg.split(' ')
       if cmdParts[0] == 'PING':
           self.sendCmd("PONG %s" % cmdParts[1])

       elif msg[0] == ':': # A server msg
           if cmdParts[1] == '001': # The welcome message, we are now connected
               self.connected = True
               self.joinChan(self.channel)
           elif cmdParts[1] == "PRIVMSG": # Whispers and chat
               channel = cmdParts[2]
               cmdParts[3] = cmdParts[3][1:] # Remove the starting colon
               if "beer" in cmdParts[3:]:
                   self.sendmsg(channel, "I like beer! CHEERS!")

 

Eksempel i vedlegg

post-141424-0-74299200-1304177995_thumb.png

Endret av etse
Lenke til kommentar

Jo, fikk det til å fungere på samme vis, bare på min litt mer tungvindte måte.. Men, problemet kommer når jeg ønsker flere kommandoer, mer morro etc.. :p

 

Forsøker å legge til flere kommandoer så krasher boten under oppstart... Merkelig mener jeg :S

 

            elif cmdParts[1] == "PRIVMSG": # Whispers and chat
               channel = cmdParts[2]
               cmdParts[3] = cmdParts[3][1:] # Remove the starting colon
               if "beer" in cmdParts[3:]:
                   self.sendmsg(channel, "I like beer! CHEERS!")
	if "haha" in cmdParts[3:]:
                   self.sendmsg(channel, "Hahaha! That is funny, I need to grab some popcorn!!!xD")

 

Hvordan får jeg lagt in flere ti-talls "kommandoer"? Det lat seg ikke gjøre se enkelt.. Den krashet bare..

Endret av tROOP4H
Lenke til kommentar

burde ikke være så ille. Bruke heller else-if etter min smak though. Dette betyr at om flere inlegg skulle bli sagt på en gang kan flere beskjeder blir sendt for en enkelt setning though.

du sier det kræsjer? Kjører du det gjennom IDLE? I så fall er det problemet. Koden din fungerer i hvertfall helt fint her.

Lenke til kommentar

"Kjører du det gjennom IDLE?"

- Jeg kjører bare "python script.py" i kommandolinja.. Leste det meg til at det var rett måte å gå frem på? :) Kan også simpelthen dobbeltklikke på scriptet, da starter det opp, men krsher instant, også.

 

Har det noe å si at jeg ikke bruker 3.2 men sitter med 2.7.1? :)

 

Fikk den til å starte, merkelig nok, uten endring... Men, da jeg satt å testet den på IRC kjedde dette ->

<tROOP4H> beer
<beerbot> I like beer! CHEERS!
<tROOP4H> hahaha
<beerbot> Hahaha! That is FUNNY! I need to grab some popcorn!!!xD
<tROOP4H> party
* beerbot ([email protected]) Quit (Read error: EOF from client)

Endret av tROOP4H
Lenke til kommentar

Jeg klarer ikke reprodusere problemet her. Kjører selv versjon 2.6.6, så versjon 3 skulle ikke være noe krav.

 

Edit: Kan det være at serveren ga deg feilmeldingen "You are trying to reconnect to fast!" ?

Scriptet har ingen håndteringer av eventuelle feil og exceptions, så om serveren skulle gi en slik feilmelding så vil programmet kræsje.

Endret av etse
Lenke til kommentar

Nei, den bare blinket.. "Startet", og "stoppet" like fort... Men, fikk den i gang med 3 kommandoer. Men alt virker bare litt fukka merkelig her...

 

           elif cmdParts[1] == "PRIVMSG": # Whispers and chat
               channel = cmdParts[2]
               cmdParts[3] = cmdParts[3][1:] # Remove the starting colon
               if "popcorn" in cmdParts[3:]:
                   self.sendmsg(channel, "Put the Beer Down and walk away with your popcorn!")
               if "beer" in cmdParts[3:]:
                   self.sendmsg(channel, "I like beer! CHEERS!")
               if "haha" in cmdParts[3:]:
                   self.sendmsg(channel, "Hahaha! That is FUNNY! I need to grab some popcorn!!!xD")

Jeg kopierer en av de statementsa over, og legger til en under, da fungerer det ofte... Men, om jeg da endrer fra "beer" til f.eks "Hei", og statement til "hei der!", så kan den krashe.. Kopierer jeg bare "clean", uten endring så fungerer det oftest.. :S

Mener det er veldig rart, og merkverdig ustabilt.. :S

Endret av tROOP4H
Lenke til kommentar

grunnen til at det blinker er vel fordi du starter det med å dobbeltklikke på fila i stede for å skrive "python bot.py", så du får ikke med deg de eventuelle feilmeldingene. Det rare er at jeg har hatt min kjørende nå i en halvtime, og den er meget stabil.

  • Liker 1
Lenke til kommentar

Vel, da var det iallefall på plass! :) Fikk scriptet til å fungere, så da må jeg lære meg litt andre smågreier, som blir brukt med boten: Python + mysql, data som skal lagres, som også skal kunne nå's med php.

Endret av tROOP4H
Lenke til kommentar

hva med å heller prøve å sette deg inn i django for å lage web-grensesnitt med python? Det er virkelig å anbefale, da blir du kjent med en stadig voksende rammeverk samtidig som du kan lære deg mer python :)

Endret av etse
  • Liker 1
Lenke til kommentar

Hei igjen! :p

 

Kom over et lite problem *sjokk* :D Virket småvanskelig å lese seg til (for meg, som er uerfaren med python) Forsøker å liste brukere fra en tabell i MySQL, på en channal, jeg får den til å starte opp, koble seg til, men den vil krashe om jeg skirver .users..

 

Happy edit:

    def parse(self, msg):
       cmdParts = msg.split(' ')
       if cmdParts[0] == 'PING':
           self.sendCmd("PONG %s" % cmdParts[1])

       elif msg[0] == ':': # A server msg
           if cmdParts[1] == '001': # The welcome message, we are now connected
               self.connected = True
               self.joinChan(self.channel)
           elif cmdParts[1] == "PRIVMSG": # Whispers and chat
               # MYSQL
               conn = mdb.connect('localhost', 'root', '', 'test');
               cursor = conn.cursor(mdb.cursors.DictCursor)
               cursor.execute("SELECT * FROM users")
               rows = cursor.fetchall()

               channel = cmdParts[2]
               cmdParts[3] = cmdParts[3][1:] # Remove the starting colon
               if ".users" in cmdParts[3:]:
                   for row in rows:
                       self.sendmsg(channel, (row["username"]))

Hoho, da har jeg klart det også! Kansje ikke vakkert.. Og ikke komplett da det lister litt feil :

<@tROOP4H> .users
<@ThePyBot> tROOP4H
<@ThePyBot> slacky

 

Slik ønsker jeg det:

<@tROOP4H> .users
<@ThePyBot> tROOP4H, slacky

 

Edit:

Ang. django, så vet jeg ikke helt hva det brukes til, har kjeldent hatt behov for rammeverk, innen php. Web-grensesnitt (nermer seg php sitt område?). Vil mer over på små "programmer" innen nettverk/web - Vekk fra browseren. Web-applikasjoner kan jeg lage i php (om det ikke er snakk om noe annet en det jeg forsto). Har grodd meg lei php-området etter 5år.

 

Starter iallefall med en liten bot, hvordan det utvikler seg, får vi se :)

Endret av tROOP4H
Lenke til kommentar

Angående django: Det er enkelt og greit et rammeverk for python som gjør at du kan lage websider som fungerer via Apache - bare med å bruke python i stede for PHP. Det minner litt om ruby on rails on du har prøvd eller hørt om det. Djang oer rett og slett bare en måte å lage websider ved å bruke python :)

 

Så la oss si du skal lage en bot som du kan styre gjennom en web-grensesnitt. Hvor kommunikasjon mellom boten og web-siden går gjennom en database. Du har skrevet boten i python, og så skriver du websiden i PHP; det kan fungere helt fint. Men hvorfor ikke bare gjøre alt i Python? ;)

 

Anbefaling:

Når du gjør store ting som kan gå galt, og om de gjør det så kræsjer programmet er det ofte fordi det skjer en exception. Til det har man "try" og "catch".

try:
   connect_to_server()
   do_stuff()
except Exception:
   print "Something bad happened here... oops!"

  • Liker 1
Lenke til kommentar

Du virker ril å ha god kjenskap, så jeg lurer på hvordan jeg skal hente ut nick fra en person?

 

Edit: Jeg spør for mye før jeg selv har testet det som er logisk å gjøre :p

	# Get Nick
               rmpt = msg.split('.')
               str = rmpt[0]
               rmalfa = str.split('@')
               nstr = rmalfa[0][1:]
               nickname = nstr.split('!')

Endret av tROOP4H
Lenke til kommentar

Jeg kan litt om IRC protokollen siden jeg holder på å prøve å lage en fullverdig klient i C#.NET for tiden. I denne versjonen har jeg laget en "back-end" IRC-klasse som jeg bruker for å lese input fra sockets og sende de til GUI til behandling.

 

Regner med du skal hente ut nick til en person når han gjør en priv-msg?

I C# bruker jeg følgende til å hente ut nicket

user = cmdParts[0].Split('!')[0].Remove(0,1);

I python blir dette noe lignende:

nick = cmdParts[0].split('!')[0][1:]

 

Om du ikke er helt med på hva den koden gjør, siden du er ny i python skal jeg prøve å forklare hva den koden gjør. Men først husk følgende fra IRC-protokollen:

1: Første argumentet er senderen av en kommando (for privmsg er det brukeren som sendte beskjeden)

2: Andre argument er kommandoen, i vårt tilfelle "PRIVMSG" som viser at det er en message.

3: Argument 3 er i hvilken kanal kommandoen ble skrevet. (om det er privat melding mellom 2 brukere er navnet på kanalen navnet på brukeren, ellers starter navnet med #)

4: For PRIVMSG er alt fra og med 4 argument selve meldingen.

5: Argument 1, med senderen, kommer på følgende format: ":NICKNAME!VHOST"

 

Koden på kompakt form gjør følgende:

Plukkter ut første argumentet fra meldingen (cmdParts[0]) og splitter denne opp en liste med hensyn på utropstegn. Den tar så å lager en ny streng fra første element i den nye listen som inneholder alle bokstaver utenom den første.

 

liste[1:] betyr rett og slett bare "plukk elementer fra 1 til SISTE ELEMENT fra listen liste". Dette fungerer og for strenger.

  • Liker 1
Lenke til kommentar

Forsto den, klarte også å få det til! :)

 

Men, kom over et problem jeg har diklet med en times tid nå...:

 

                    if "!cl" in cmdParts[3:]:
                       cpt = cmdParts[4]
                       try:
                           self.sendmsg(channel, ""+ nickname[0] +" just challanged "+ cpt +".")
                           self.sendmsg(channel, "A new game has started, type !sign to join the game.")
                       except Exception:
                           print "Error in !cl"

Om de bare skriver !cl vil botten crashe.. Jeg kommer meg ikke rundt den, har forsøkt mye rart.

EDIT: Selvfølgelig forsøker jeg ikke det som er åpenbart! Nei, nå trenger jeg en pause snart :)

- alt jeg ble nødt til var å "putte" cpt = cmdParts[4], inn i try:

Endret av tROOP4H
Lenke til kommentar

Når det kommer til strenger i python, lær deg å bruke formatering; gjør det mye enklere å lese.

 

>>> tall = 16

>>> streng = "En tekst-streng"

>>> print "Tallet vårt er %d, og strengen vår er '%s'." % (tall, streng)

Tallet vårt er 16, og strengen vår er 'En tekst-streng'.

 

Rett og slett bare skriv en streng hvor du setter inn %d der du ønsker tall, %s der du ønsker tekst-strenger og %f der du ønsker desimal-tall. Legg så argumentene til på slutten slik jeg har gjort, i rekkefølgen argumentene kommer i teksten. Det gjør tekst-strengene mye enklere å lese; spesielt når man har flere argumenter inni midten av setningene.

 

Angående feilen din, er jeg ikke helt fan av måten du gjør det. Slik du har skrevet det nå vil den og reagere om jeg skriver "kommandoen er !cl" i chaten. Er vel bedre å sette som krav at det skal være det første ordet når det er kommandoer til boten?

 

Prøv heller noe slik:

if "!cl" == cmdParts[3][1:]
   if len(cmdParts) != 5:
       self.sendmsg(channel, "%s: invalid use of command. Use '!cp username'" % (nickname[0]))
   else:
       self.sendmsg(channel, "%s just challanged %s." % (nickname[0], cmdParts[4]))
       self.sendmsg(channel, "A new game has started, type !sign to join the game.")

  • Liker 1
Lenke til kommentar

Skal huske på det til jeg fortsetter med scriptet! :)

"kommandoen er !cl" vil forrasten ikke bli lagt merke til.. Takket være split(' '), så den vil bare lagge merke til første ordet.

 

Men, måten jeg koder på er ganske klumsete, er nybegynnerkoding :)

 

En sak jeg ikke skjønner hvordan jeg skal gjøre, selv med MASSE googling (kom bare frem til CSV ett eller annet)

Hvordan skal jeg separere output fra flere rader i mysql med komma? Må jeg gjøre noe ninja-klomsegreier, slik jeg bruker å gjøre når jeg ikke får til?

 

                cursor.execute("SELECT * FROM users")
               rows = cursor.fetchall()
               if "!users" in cmdParts[3:]:
                   for row in rows:
                       self.sendmsg(channel, (row["username"]))

Nå looper jeg utenfor self.sendmsg, noe som ikke er slik jeg ønsker.

 

Samt, over på IRC-delen... Ser ofte at boter skriver/svarer utenfor nicket..

 

f.eks:

<asd> spam
<asd> spam
<asd> spam
* @SpamBot hey stop spam, i dont like it!
<asd> ...

Er det magi? :p

Endret av tROOP4H
Lenke til kommentar

om du er på IRC er det du nevner til på slutten der ikke magi. Fleste klienter støtter "/emote is running up a cliff."

 

En standad beskjed sendes op følgende måte:

"PRIVMSG #channel : The message to be sent"

 

skal du sende emotes skal den være følgende:

"PRIVMSG #channel :\x01ACTION the emote I am doing\x01"

hvor \x01 er det andre tegnet i ASCII-tabellen.

 

Eksempel er å lage en ny metode som heter "sendemote" i stede for "sendmsg":

def sendemote(self, channel, emote):
    self.sendcmd("PRIVMSG %s :\x01ACTION %s\x01" % (channel, emote))

self.sendemote(chan, "just joined the channel!")

 

angående det å gå ting på linje, hva med å først lage en string i løkken din? og så sende den etterpå? (er ikke kjent med mySQL sammen med python).

Blir noe slikt som:

outputString = ""
for row in rows:
   outputString += row + ", "
self.sendmsg(channel, outputString)

  • Liker 1
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...