2012. júl. 21.

OTP egyenleget naponta Google Docs-ba automatikusan

Update: Téma erről a posztról HUP-on: http://hup.hu/node/120903

Előzmény

Egy szép nyáron napon volt pár e-mail a Gmail fiókomban, amikkel csak 1 hét múlva kellett volna valamit kezdenem, és zavart, hogy ennek ellenére minden nap ott néznek rám. Egy kis guglizással rátaláltam erre:
http://lifehacker.com/5825634/how-to-add-a-snooze-button-to-gmail-no-extensions-required
Már a cikk címe felkeltette a érdeklődésem, mert elképzelésem nem volt, hogy hogyan lehetséges ez bármiféle kiterjesztés vagy harmadik félnek történő jelszókiadás nélkül.
Lehetséges, és a varázslat része a dolognak a Google Scripts, ami lehetővé teszi számunkra, hogy minden nap megadott időben lefutó javascript nyelvű felhőben tárolt scripteket írjunk, amik nagyon kényelmes javascriptes api-n hozzáférhetnek Google szolgáltatásainkhoz, mint például a Gmailhez vagy a Docs-hoz.
Ennek a scriptnek a kódjáról nem fogok beszélni. Ha érdekel, akkor megtalálod az eredeti linken.

 

Kényszer

Aztán jött a kényszer, hogy valamire használnom kell ezt a Google Script-et a Gmail Snooze-on felül.. Itt jött az ötlet, hogy milyen király(?) lenne, ha láthatnám a banki egyenlegem alakulását egy grafikonon Google Docsban.

 

Kérés

Az OTP biztosít egy a normál netbanktól független felületet, ahol a telekóddal és kártyaszámmal le lehet kérdezni az aktuális egyenleget. A telekód alapból a számlaszám utolsó 3 számjegye. Ez a felület az OTPdirekt belépés gomb alatt található jelenleg:
OTP-egyenleg
Direkt link az OTP egyenleglekérdezés leírására

Itt a kártyaszám és a telekód megadása utána megkaphatjuk az aktuális egyenlegünk:
image[3]
Hm… Ezt a lekérdezést szeretnénk valahogy automatizálni.

Nézzük meg az űrlapot, ami beküldünk:
(Chrome-ban dolgozom.)
image
Katt az “Elem megtekintésére”.
Ekkor a Chrome feldobja az Elements Panel-t:
image
A method=”post”-ból láthatjuk, hogy ez egy POST kérés lesz. A kérésben a következő mezők fognak utazni:
muvelet
azonosito
telekod
honlapAzonosito
azonositoxx
telekodxx

Ezekből mi csak kettőnek állítjuk az értékét, és értelemszerűen ezek az azonositoxx és telekodxx. A többit alapértéken hagyjuk.
Valójában ha jobban megnézzük, akkor tévedtem, mert az azonositoxx  és a telekodxx az beküldéskor üres lesz az onsubmit eseménykezelő hatására, és a tartalmuk átíródik a rejtett azonosito es telekod mezőkbe. (Ezt azért csinálták, mert nem akarták, hogy a böngésző felajánlhassa a jelszó elmentését, valamint így a Vissza gomb megnyomása után a böngésző nem tudja visszaállítani a kitöltött állapotát az űrlapnak.)

Eddig feltételezésink helyességéről meggyőződhetünk, ha elkezdjük figyelni az oldal forgalmát a Network fülön, és beküldünk egy kérést.
Ehhez váltsunk át a Network fülre (Az Elements fültől 2-vel jobbra.), és aztán a szokványos módon küldjük be az űrlapot. Ezután kattintsuk rá a “bankkartyaEgyenlegLekerdezes” kérésre, és keressük a Form Data részt.
image
Úgy tűnik, hogy mindent helyesen láttunk.
Kipróbálhatjuk mondjuk wget-el (opcionális):
wget https://www.otpbankdirekt.hu/homebank/do/bankkartyaEgyenlegLekerdezes -O - --post-data "muvelet=login&azonosito=██████████&telekod=███&honlapAzonosito=Default.User&azonositoxx=&telekodxx="
(Ez a parancs egy sor.)


Ha minden jól sikerült, akkor a wget hatására láthatjuk a lekérdezés eredményét egy csomó html kód közt.

Megvan, hogy hogyan tudjuk lekérdezni. Akkor most ebből valahogy Google Script-et kéne csinálni.

Script

Hozzunk létre egy új Google Táblázatot, nyissuk meg, és az Eszközök menüből válasszuk ki a Script szerkesztőt. Ekkor kapunk egy nagyon segítőkész ablakot, amit csukjunk is be.

Ekkor ezt kell látnunk:
image
A kis “Play” gombbal lefuttathatjuk a myFuncton-t, ami jelenleg nem csinál semmit. (Ekkor el kell mentenünk a Project-et. Mentsük tetszőleges néven.)

Csináljunk valami extravangásabbat:
image

Mikor ezt lefuttatjuk, akkor első pillantásra nem történik semmi, pedig valójában megjelent egy üzenetablak, de nem ott ahol vártuk, hanem az eredeti dokumentumban:

image

Az elérhető API-kat itt találod: https://developers.google.com/apps-script/defaultservices

Például megtalálhatjuk a UrlFetchApp.fetch metódust, ami jó szolgálatot fog nekünk tenni. Ezzel fogjuk lekérni az egyenlegünket.
A korábban összehozott lekérés és a dokumentáció alapján a következő kódot állítjuk elő:
image

Ez ugyanaz a lekérés, ami korábban kipróbáltunk. Próbáljuk ki itt is:
image

… és az eredmény:
image
A lekérés a title alapján működni látszik….. Már csak valahogy ki kéne nyerni belőle a lényeget. Html-ből infót kinyerni nem szép, de hasznos.

A következő buta, de működő megoldást választottam: Az első <span class="value"><strong> és </strong> közötti cucc érdekel minket:
var egyenleg = response.getContentText().split('<span class="value"><strong>')[1].split("</strong>")[0];

Valamint még a pontot is kéne kapni belőle, mert számot szeretnénk:
var egyenleg = response.getContentText().split('<span class="value"><strong>')[1].split("</strong>")[0].replace(".","");

Így a következő tesztelhető kódhoz jutunk:
image

… amit ha lefuttatunk, akkor most már ténylegesen az egyenlegünket kapjuk a dobozba:
image

Ez szép és jó, de mi grafikont szeretnénk.

A grafikonhoz először meg lennie az adatnak táblázatosan. Mondjuk így:
image

Ezután kijelöljük az A és B oszlopot egyszerre, és hozzáadunk a dokumentumhoz egy vonaldiagramot. Azon kicsit állítgatunk, és akkor valami ilyesmit kaphatunk:
image
Azért volt fontos az egész A és B oszlopot kijelölni, mert így ha egy új sorba beleírunk valamit, akkor így az is felkerül a diagramra, és így akkor most már tényleg csak az a magic kell, ami minden nap hozzáad egy új sort ehhez a táblázathoz a megfelelő értékekkel.

Az eddig elkészült függvényünket alakítsuk át egy segédfüggvénnyé, ami az egyenleggel tér vissza visszatérési értékként. Ehhez egyszerűen cseréljük le az msgBox-os sort erre:
return egyenleg;

Ezután írjuk meg a következő függvényt, ami hozzáadja a megfelelő értékekkel rendelkező új sort:
image

Láthatjuk, hogy ez felhasználja korábban megírt getOtpEgyenleg függvényünket.
Az “otp-egyenleg” a munkalap neve. Ez neked lehet, hogy más.
A dátumot azért ilyenre formázom, mert (többek közt?) ezt ismeri fel a Docs dátumnak.

Ha ezt a függvényt lefuttatjuk a kis Play gombbal, akkor láthatjuk, hogy hozzáadódik egy új sor a táblázathoz, és a diagram is frissül.

Egyetlen lépés van már csak hátra: Beállítani, hogy minden este automatikusan lekérje az aktuális egyenleget:
Resources menü → Current script’s triggers → és ott adjuk hozzá a következő sort:
image

Mentsük, és ezzel készen is vagyunk. Minden éjjel magától frissülni fog a táblázatunk. :)

Yéy!

 

A kód másolható formában

function getOtpEgyenleg() {
  
  var url  = "https://www.otpbankdirekt.hu/homebank/do/bankkartyaEgyenlegLekerdezes";
  var payload = 
    {
      "muvelet" : "login",
      "azonosito" : "██████████",
      "telekod" : "███",
      "honlapAzonosito" : "Default.User",
      "azonositoxx" : "",
      "telekodxx" : ""
    };
  var options =
    {
      "method" : "post",
      "payload" : payload
    };

  var response = UrlFetchApp.fetch(url, options);
  
  var egyenleg = response.getContentText().split('<span class="value"><strong>')[1].split("</strong>")[0].replace(".","");
  return egyenleg;
}

function updateSpreadSheetWithNewRow() {
  var egyenleg = getOtpEgyenleg();
  var date =  Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd");
  
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("otp-egyenleg");
  
  sheet.appendRow([date, egyenleg]);
}

Még egy kis kiegészítés (aktuális egyenleg)


Néha jó lenne rögtön itt látni az aktuális egyenleget (nem csak a tegnap estit).

Erre csináltam egy függvényt, ami beírja azt egy cellába, és létrehoztam egy trigger-t, ami a doksi megnyitásánál lefuttatja.
function updateSpreadWithCurrentBalance(){  
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("otp-egyenleg");
  sheet.getRange("E2").setValue("Updating...");
  SpreadsheetApp.flush();
  var egyenleg = getOtpEgyenleg();
  sheet.getRange("E2").setValue(egyenleg);
}

…és a trigger:

image