poniedziałek, czerwca 06, 2016

Jak nie zapomnieć kupić biletu miesięcznego ;-)

Jako jednostka z natury leniwa staram się ograniczać swoje działania do absolutnego minimum.
Stąd bilet miesięczny na tramwaj kupuję 2 razy w roku, od razu na 6 miesięcy*.
Dodatkowo dostaję bonus w postaci jakieś tam zniżki.

Ma to jednak ten minus, że muszę zawsze pamiętać by ustawić sobie w kalendarzu przypominajkę...
A przynajmniej tak musiałem robić do wczoraj ;-)

Bo wczoraj postanowiłem zautomatyzować proces pilnowania kupna biletu.

Na 31, 21, 14, 7 i 1 dzień przed końcem ważności biletu dostanę maila z przypomnieniem (oczywiście jeśli np. po 1 mailu z okazji 31 dni kupię nowy bilet to nie dostanę już kolejnych maili).

Magia, która to robi jest w Pythonie i wygląda tak jak poniżej ;-)

#!/usr/bin/python
import urllib2
import sendmail
import datetime
import os

id = "<numer legitymacji KMK>"
cityCardNumber = "<nr seryjny karty>"
cityCardType = "0"
SEND_TO="<mail na ktory ma przyjsc informacja>"
limits = [31,21,14,7,1]

def getUrl(id, cityCardType, cityCardNumber):
url = "http://www.kkm.krakow.pl/pl/sprawdz-waznosc-biletow-zapisanych-na-karcie/index,1.html?cityCardType="+cityCardType+"&identityNumber="+id+"&cityCardNumber="+cityCardNumber+"&sprawdz_kkm=Sprawd%C5%B$
return url

def getDateFor(id, cityCardType, cityCardNumber):
MARKER = "Data ko"
url = getUrl(id, cityCardType, cityCardNumber)
lines=urllib2.urlopen(url).readlines()
str="".join(lines)
date=None
if str.count(MARKER):
idx=str.index(MARKER)+27
substr = str[idx:idx+20]
date = substr[:substr.index("<")]
return date

date = getDateFor(id, cityCardType, cityCardNumber)

if not date:
url = getUrl(id, cityCardType, cityCardNumber)
sendmail.sendEMail(SEND_TO,u"[KMK watchdog] lack of date",u"""Cannot find end of period date on """+url+"""
Page was changed?
Or you don't have KKM?""")
else:
d = datetime.datetime.strptime(date,"%Y-%m-%d")
daysTillDate = (d-datetime.datetime.now()).days
for limit in limits:
if daysTillDate<limit:
fName=date+"_"+str(limit)
if not os.path.exists("kmk_watchodg"):
os.mkdir("kmk_watchodg")
if not os.path.exists("kmk_watchodg/"+fName):
sendmail.sendEMail(SEND_TO,"[KMK watchdog] only "+str(limit)+" days till end of KMK","""Hi,
It seems that you have only """+str(limit)+""" days to end of your KMK card.
Go to http://www.kkm.krakow.pl to buy new ticket, or disable this alarm on Raspberry Pi.""")
f=open("kmk_watchodg/"+fName,"w+")
f.write(str(datetime.datetime.now()))
f.close()


Skrypt dodany jest do crontaba na jednym z moich Raspberry Pi i uruchamia się raz dziennie.

Można spytać czemu skrypt pisze do mnie po angielsku...
Odpowiadam - bo polskie literki w Pythonie mnie przerastają ;-)

Skrypt może się też posypać jeśli zmieni się struktura strony... wtedy trudno, ale dostanę maila z informacją o tym ;-)

Cały "mechanizm" nie otrzymywania maili ponownie opiera się na plikach ;-) po prostu po wysłaniu maila dla danej daty i limitu skrypt tworzy plik który mu w razie czego powie, że mail już został wysłany (niby skrypt jest odpalany raz dziennie, ale mógłby być odpalany częściej, a i tak by działał).

Wysyłanie maili wykonuje ten kawałek (sendmail.py):

import urllib2
import smtplib
import sys
from datetime import datetime

FROM = "<adres z ktorego wysyłamy>"
PWD = "<haslo do konta>"
# jesli hasło i user są z GMAILa to trzeba osłabić jego bezpieczeństwo, dlatego ja mam oddzielne konto do wysyłania takich maili.

def _sendEMail(usr, psw, fromaddr, toaddr, subject, content):
runtime=datetime.now()
server=smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(usr,psw)
senddate=datetime.strftime(datetime.now(), '%Y-%m-%d')
m="Date: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nX-Mailer: My-Mail\r\n\r\n" % (senddate, fromaddr, toaddr, subject)
msg=content
server.sendmail(fromaddr, toaddr, m+msg)
server.quit()

def sendEMail(toaddr, subject, content):
_sendEMail(FROM,PWD,FROM,toaddr,subject,content)


Tu warto dodać, że konto, którego używam do wysyłania maili jest całkiem niezależne od moich kont, specjalnie w Google Apps for Domain stworzyłem 1 konto do takich działań.

Tak oto lenistwo prowadzi do pracy i tworzenia skryptów by można było nadal być leniwym ;-)



* - można by spytać czemu na 6 miesięcy, a nie na 12, odpowiedzią jest to, że nie do końca wiem co będzie za rok, pewnie będzie tak samo jak teraz, ale jednak nie mam tej pewności i może np. przeprowadzę się do innego miasta? Wtedy mogłoby się okazać, że przez pół roku albo i dłużej bym nie korzystał, a i tak bym zapłacił. Przy 6 miesiącach ryzyko jest mniejsze.


Podobne postybeta
Jak nie zapomnieć kupić biletu miesięcznego - revised ;-)
Jak się dowiedziałem o tym, że w Polsce rusza Google Play Movies ;-)
Polowanie na Nexus 4 - wersja automagiczna ;-)
SleepAdvisor - komórka pomaga w wyspaniu się ;-)
Monitorujemy cenę IntelliJ'a ;-)