devboard: Żeby nudno nie było - bot czytający bash.org.pl - devboard

Skocz do zawartości

Strona 1 z 1
  • Nie możesz napisać tematu
  • Nie możesz odpowiedzieć

Żeby nudno nie było - bot czytający bash.org.pl

#1 Użytkownik nie jest zalogowany   pbnan

  • Młodszy Programista
  • PipPip
  • Grupa Użytkownicy
  • Postów 12
  • Rejestracja 13-marzec 09
  • Płeć:Male
  • Skąd:Poland/Oświęcim

Napisano 16 maj 2009 - 09:54

Dotychczas brakowało mi kogoś inteligentnego do rozmowy ;] Więc postanowiłem sobie napisać bota. Jako że ani na IRC-u codziennie nie siedzę, ani pulpitu nie oglądam zbyt często (okna go zasłaniają), tak też bot miał obsługiwać jedno z moich kont Jabber.

Dobranie odpowiedniego serwera, tak dla skryptu, jak i konta IM nie jest celem tego tutorialu, więc nie wspomnę tutaj w ogóle o jakości i stabilności serwera **** ;)

Gdy przychodzi co do czego, uczeń mistrza Pythona ma do wyboru kilka ostrzy - xmpppy, jakiś python-xmpp z LP, pyxmpp oraz jabber.py. W ciągu ostatniego roku korzystałem chyba z większości z nich, niemniej jednak do tej pory nie wyrobiłem sobie konkretnego zdania na ich temat. Z pewnością python-xmpp z Launchpadu nie jest dobrym wyborem - nie ma określonej licencji.

Do tego "projektu" wybrałem xmpppy - ma całkiem fajną dokumentację.

Jeszcze słówko o założeniach: przy uruchomieniu jak i zmianie godziny, bot ma wysyłać do wszystkich w swoim rosterze wylosowany cytat z bash.org.pl.

Klasa ogólnie będzie miała postać:
class Client:
  def __init__(self):
	...
  def send_content(self):
	...


Na początku zdefiniujmy parę przydatnych zmiennych. Ich znaczenie jest, mniemam, przejrzyste.
class Client:
	login = "bot"
	domain = "example.org"
	password = "abecadlo_z_pieca_spadlo"


Przenieśmy się teraz do metody __init__.
		self.jid = xmpp.JID(node=self.login, domain=self.domain, resource="Botownica")
		self.client = xmpp.Client(server=self.jid.getDomain(), debug=[])
		
		self.client.connect()
		self.client.auth(self.jid.getNode(), self.password,
						 self.jid.getResource())
		
		self.client.sendInitPresence(True)
		
		self.roster = self.client.getRoster()

Cały ten "ogromny" kod odpowiada za połączenie się z serwerem, zalogowanie oraz ustawienie obecności i pobranie listy kontaktów (rostera).

Klasa xmpp.JID nie robi nic ważnego, jest w zasadzie zwykłym pojemnikiem na ustawienia danego konta, jak na przykład login czy zasób. W tym kodzie zasób ustawiliśmy na "Botownica" :)

Natomiast klasa xmpp.Client jest już ważna. Dziedziczy ona po CommonClient i pomaga ustanowić połączenie szyfrowane (całkiem automagicznie), jak również ułatwia ustawianie obecności.

W następnych liniach łączymy się z serwerem i autentyfikujemy, potem wysyłamy obecność self.client.sendInitPresence(True) - True oznacza, że po zalogowaniu pobrany zostanie roster, który sobie "bierzemy" w ostatniej linii.

		file = "bash.txt"
		if not os.access(file, os.F_OK):
			import urllib2
			address = "http://bash.org.pl/text"
			data = urllib2.urlopen(address).read()
			with open(file, "w") as f:
				f.write(data)
		
		if os.access(file, os.R_OK):
			self.data = open(file).read()
			self.data = self.data.split("%\n")
		else:
			self.data = []

Ostatnie linie w metodzie __init__. Jako że bash.org.pl udostępnia tekstową wersję swoich cytatów, pobieramy ją, ale tylko wtedy, gdy jeszcze pobrana nie została. Dlaczego? Plik waży 1.7MB, przecież nie będzie pobierany co uruchomienie się skryptu.

Gdy uporamy się z pobraniem, staramy się go przeczytać i podzielić na osobne wpisy. Na szczęście są one wszystkie odseparowane przez linię ze znakiem procentu.

Nadszedł czas na metodę send_content, która wysyła do wszystkich w rosterze losowy cytat.
		message = random.choice(self.data)
		for i in self.roster.keys():
			if i != self.login+"@"+self.domain:
				self.client.send(xmpp.protocol.Message(i, message))

W pierwszej linii przypisujemy do message losowy cytat. Następuje pętla przez wszystkie klucze z rostera. Muszę tutaj wytłumaczyć, dlaczego dodałem tego IFa wewnątrz. Otóż, z niewiadomych mi przyczyn, roster przykładowego konta dla mojego bota zawiera sam siebie, dlatego też trzeba go wyfiltrować. Potem zostaje wysłana wiadomość (xmpp.protocol.Message(adresat, treść)) i... To w zasadzie wszystko.

Dodatkowo podam poniżej kod, dzięki któremu co godzinę (a konkretnie co zmianę godziny) będzie wywoływana przed chwilą opisana metoda send_content:
if __name__=="__main__":
	c = Client()
	
	try:
		c.send_content()
		
		last_hour = time.strftime("%H")
		while 1:
			if time.strftime("%H")!=last_hour:
				c.send_content()
				last_hour = time.strftime("%H")
			time.sleep(60)
	except KeyboardInterrupt as x:
		pass

Ważny fragment jest w bloku try: najpierw następuje wysłanie początkowe, tzn. tuż po zalogowaniu. Następnie co minutę, w pętli, sprawdzana jest, i porównywana z dotychczasową, godzina. Jeżeli się zmieniła, to należy wysłać cytaty oraz uaktualnić zmienną last_hour.

Życzę miłej zabawy i eksperymentowania z modułem xmpppy. A nuż powstanie nam powerful klient Jabbera w Pythonie? :)
0

#2 Użytkownik nie jest zalogowany   pagenoare

  • CakeCoder
  • PipPip
  • Grupa Administratorzy
  • Postów 19
  • Rejestracja 02-grudzień 08
  • Płeć:Male
  • Skąd:Toruń

Napisano 20 maj 2009 - 21:13

Cytat

with open(file, "w") as f:


W pythonie 2.5 nie zadziała bez importu:
from __future__ import with_statement


Pozatym, nie jest to tutorial dla początkujących, nie ma nic o potrzebnych importach (e.g. os) [:
0

#3 Użytkownik nie jest zalogowany   pbnan

  • Młodszy Programista
  • PipPip
  • Grupa Użytkownicy
  • Postów 12
  • Rejestracja 13-marzec 09
  • Płeć:Male
  • Skąd:Poland/Oświęcim

Napisano 21 maj 2009 - 18:31

Czy napisałem, że to jest dla początkujących? :] Zasadniczo, jeśli miałbym uczyć początkujących, to wymuszałbym na nich samodzielność w rozwiązywaniu problemów - tj. w szukaniu w dokumentacji, między innymi.

Jeśli chodzi o niekompatybilność, to Python 2.6 zgłasza warning użycia przestarzałej biblioteki do SSL.

Natomiast w bloku try-except (ostatni codebox) pojawia się ponownie statement "as", który nie działa w Pythonie 2.5 - zamiast niego można użyć zwykłego przecinka.
0

Strona 1 z 1
  • Nie możesz napisać tematu
  • Nie możesz odpowiedzieć

Użytkownicy przeglądający ten temat: 1
0 użytkowników, 1 gości, 0 anonimowych