MoneyMoney

Einführung

Warum Web Scraping?

Viele Banken betreiben mittlerweile einen FinTS/HBCI-Server für Finanzsoftware. Einige Banken bieten jedoch leider überhaupt keine maschinenlesbare Schnittstelle an, über die eine Finanzsoftware (wie MoneyMoney) die Umsätze abrufen könnte. In so einem Fall können die Umsätze von einer Finanzsoftware nur mittels Web Scraping von der Website der Bank heruntergeladen werden.

Die Web Banking Engine

Die Web Banking Engine von MoneyMoney besteht aus einem recht umfangreichen Kern, der in C und Objective-C implementiert ist. Der Kern wird durch mehrere schlanke Extensions ergänzt. Diese Web Banking Extensions sind kurze Lua-Skripte, die einfach zu erstellen, zu modifizieren und auszuwechseln sind. Die Lua-Skripte werden von der Web Banking Engine in einer virtuellen Maschine ausgeführt und kommunizieren über eine dokumentierte API mit MoneyMoney. Das vorliegende Dokument spezifiziert diese API.

Die Wahl der Skriptsprache fiel auf Lua, da sie relativ leicht zu erlernen ist und sich gut mit C/C++/Objective-C kombinieren lässt. Für unsere Extensions reicht es vollkommen aus, die ersten fünf Kapitel von »Programming in Lua« gelesen zu haben. Die meisten innerhalb einer Extension aufgerufenen Funktionen sind nämlich gar nicht Bestandteil von Lua, sondern existieren ausschließlich in MoneyMoney.

Ein Praxisbeispiel

Das folgende Stück Lua-Code soll einen Eindruck davon vermitteln, wie eine Web Banking Extension in der Praxis vorgeht:

➊ connection = Connection()
  html = HTML(connection:get("https://moneymoney-app.com/onlinebanking"))
➋ html:xpath("//input[@name='kontonummer']"):attr("value", username)
  html:xpath("//input[@name='pin']"):attr("value", password)
➌ connection:request(html:xpath("//input[@name='loginbutton']"):click())

Zuerst wird die Login-Seite vom Server geholt und aus ihrem HTML-Code eine Baumstruktur aufgebaut ➊. Mit Hilfe dieser Baumstruktur wird im HTML-Dokument mit XPath-Ausdrücken zu den Texteingabefeldern navigiert. Deren HTML-Attribute value werden dann mit den Anmeldedaten ausgefüllt ➋. Danach wird das Login-Formular abgeschickt ➌. Offensichtlich sind nur wenige Code-Zeilen notwendig, um den typischen Anmeldevorgang beim Online-Banking durchzuführen.

Das Skript erzeugt das gleiche Ergebnis, also die gleiche Serverkommunikation, wie sie ein Mensch mit einem Webbrowser beim Ausfüllen derselben Login-Seite erzeugen würde. Die Web Banking Engine kann man daher mit einem automatisch gesteuerten Webbrowser vergleichen.

Vom Skript zur Extension

Installation

Das Verzeichnis, in dem eigene Extensions abgelegt werden, kann über Menü Hilfe → Zeige Datenbank im Finder im Finder geöffnet werden:

~/Library/Containers/com.moneymoney-app.retail/Data/Library/Application Support/MoneyMoney/Extensions

Jede Änderung an Dateien in diesem Verzeichnis wirkt sich unmittelbar auf die Web Banking Engine aus, d.h. es ist nicht nötig, MoneyMoney neu zu starten.

Fehlermeldungen werden im Protokoll-Fenster von MoneyMoney angezeigt. Das Protokoll-Fenster lässt sich mit der Menüfunktion »Fenster« → »Protokollfenster« erreichen.

Hinweis: Für die Entwicklung eigener Extensions lässt sich die Überprüfung der digitalen Signatur in den Einstellungen von MoneyMoney ausschalten. Dazu wird eine Beta-Version von MoneyMoney benötigt. Die Option lässt sich mit der Menüfunktion »MoneyMoney« → »Einstellungen« → »Erweiterungen« → »Digitale Signatur von Extensions überprüfen« erreichen.

Registrierung einer Extension

Ein Skript weist sich als Web Banking Extension aus, indem es am Beginn des Skripts einen Aufruf der Art

WebBanking{version     = 1.00,
           url         = "https://moneymoney-app.com/onlinebanking",
           services    = {"Premium Account"},
           description = "Demo"}

enthält. Bei den benannten Parameter der Funktion WebBanking handelt es sich um:

  1. Number version: Versionsnummer der Extension
  2. String url (optional): URL der Einstiegsseite des Online-Bankings
  3. Array services (optional): Die in diesem Array enthaltenen Service-Namen werden in MoneyMoney in der Auswahlliste beim Anlegen eines Kontos angezeigt.
  4. String description (optional): Beschreibung der Extension

Lua-Laufzeitumgebung

Die Parameter der Funktion WebBanking sind später im Skript als globale Variablen version, url, services und description zugänglich. Zusätzlich ist auch noch die globale Variable extensionName mit dem Namen der Extension definiert.

Die Variablen MM.productName und MM.productVersion enthalten Informationen zur Anwendung, also MoneyMoney.

Die Ausgabe der Standard-Funktion print wird im Protokoll-Fenster von MoneyMoney angezeigt.

Die Standard-Funktion error bricht die Ausführung des Skripts ab. Die Fehlermeldung wird im Protokoll-Fenster und je nach Kontext auch in einem GUI-Dialog angezeigt.

Das Objekt LocalStorage kann über die Laufzeit des Skripts hinaus zur Speicherung von Informationen genutzt werden.

Das Skript selbst muss UTF-8-kodiert sein und es werden auch alle Strings als UTF-8-Strings zwischen dem Skript und MoneyMoney übergeben, außer es steht in der API-Beschreibung, dass es sich um Binärdaten handelt.

Aufbau einer Web Banking Extension

Einsprungspunkte

Die Web Banking Engine treibt die Ausführung des Skripts, was bedeutet, dass jedes Skript bestimmte Funktionen als Einsprungspunkte zur Verfügung stellen muss.

Es gibt zwei Anwendungsfälle, für die MoneyMoney die Web Banking Engine startet:

  1. Für den Anwendungsfall Bankzugang einrichten ruft die Web Banking Engine nacheinander folgende Funktionen des Skripts auf:

    • SupportsBank (Klärung der Zuständigkeit)
    • InitializeSession (Anmeldung)
    • ListAccounts (Auflistung der verfügbaren Konten)
    • für jedes Konto: RefreshAccount (Aktualisierung eines Kontos)
    • EndSession (Abmeldung)
  2. Der Anwendungsfall Kontenrundruf läuft ähnlich ab:

    • SupportsBank (Klärung der Zuständigkeit)
    • InitializeSession (Anmeldung)
    • für jedes Konto: RefreshAccount (Aktualisierung eines Kontos)
    • EndSession (Abmeldung)

Klärung der Zuständigkeit

Um herauszufinden, welche Extension für welchen Bankzugang zuständig ist, ruft die Web Banking Engine diese Funktion auf:

function SupportsBank (protocol, bankCode)

Parameter:

  1. Konstante protocol: Protokoll des Bankzugangs; Mögliche Werte sind ProtocolFinTS und ProtocolWebBanking. Der erste Wert ist dazu gedacht, einen FinTS/HBCI-Bankzugang um Konten zu bereichern, die von der Bank nicht über das FinTS/HBCI-Protokoll zur Verfügung gestellt werden. Der zweite Wert ist für Bankzugänge gedacht, die aussschließlich über Web Scraping abgefragt werden.
  2. String bankCode: Bankleitzahl oder Service-Name

Mögliche Rückgabewerte:

  • false, wenn die Extension für den besagten Bankzugang das Web Scraping nicht übernehmen kann.
  • true, wenn die Extension für den besagten Bankzugang das Web Scraping übernehmen kann. Anstelle von true kann auch die URL der Einstiegsseite des Online-Bankings zurückgegeben werden.

Anmeldung (einfach)

Diese Funktion führt einen einfachen Anmeldevorgang durch:

function InitializeSession (protocol, bankCode, username, reserved, password)

Parameter:

  1. Konstante protocol: Protokoll des Bankzugangs; Mögliche Werte sind ProtocolFinTS und ProtocolWebBanking.
  2. String bankCode: Bankleitzahl oder Service-Name
  3. String username: Benutzername
  4. String reserved: leer, derzeit nicht verwendet
  5. String passwort: Passwort

Mögliche Rückgabewerte:

  • Nichts oder nil, wenn die Anmeldung erfolgreich war.
  • Die Konstante LoginFailed, wenn die Zugangsdaten vom Server abgewiesen wurden. Um eine Sperrung des Passworts durch den Server zu vermeiden, werden die betroffenen Konten durch MoneyMoney nicht mehr automatisch aktualisiert, bis die Zugangsdaten durch den Anwender erneut eingegeben wurden.
  • Ein String mit einer Fehlermeldung.

Anmeldung (mit Zwei-Faktor-Authentifizierung)

Diese Alternative zur Funktion InitializeSession führt einen Anmeldevorgang mit Zwei-Faktor-Authentifizierung durch. Wenn diese Funktion beim ersten Aufruf ein Objekt mit Informationen zur Zwei-Faktor-Authentifizierung zurückgibt, dann wird sie ein zweites Mal mit step=2 aufgerufen. Beim ersten Aufruf enthält credentials die Benutzernamen und das Passwort. Beim zweiten Aufruf enthält credentials die Antwort auf challenge.

function InitializeSession2 (protocol, bankCode, step, credentials, interactive)

Parameter:

  1. Konstante protocol: Protokoll des Bankzugangs; Mögliche Werte sind ProtocolFinTS und ProtocolWebBanking.
  2. String bankCode: Bankleitzahl oder Service-Name
  3. Number step: Schritt 1 oder 2 der Zwei-Faktor-Authentifizierung
  4. Array credentials: Liste von Benutzernamen und Passwörtern
  5. Boolean interactive: MoneyMoney wird im Vordergrund oder Hintergrund ausgeführt

Mögliche Rückgabewerte:

  • Nichts oder nil, wenn die Anmeldung erfolgreich war.
  • Die Konstante LoginFailed, wenn die Zugangsdaten vom Server abgewiesen wurden. Um eine Sperrung des Passworts durch den Server zu vermeiden, werden die betroffenen Konten durch MoneyMoney nicht mehr automatisch aktualisiert, bis die Zugangsdaten durch den Anwender erneut eingegeben wurden.
  • Ein String mit einer Fehlermeldung.
  • Ein Objekt mit folgenden Feldern:

    • String title: Überschrift für den Dialog der Zwei-Faktor-Authentifizierung
    • Binary challenge: Die Aufforderung kann entweder ein String für eine Frage sein, oder die Binärdaten eines Captchas im PNG- oder JPEG-Format.
    • String label: Beschriftung des Eingabefelds

Auflistung der verfügbaren Konten

Diese Funktion listet alle Konten auf, die mittels Web Scraping abgefragt werden können:

function ListAccounts (knownAccounts)

Parameter:

Array knownAccounts: Wenn das Protokoll des Bankzugangs FinTS/HBCI ist, Web Scraping also nur als Ergänzung dient, dann enthält dieser Parameter ein Array mit schon bekannten Konten. Das Skript kann anhand dieses Arrays feststellen, welche Kontoinformationen es nicht mehr über Web Scraping abzufragen braucht. Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur eines Kontos« beschrieben.

Mögliche Rückgabewerte:

  • Ein Array mit Konten, die mittels Web Scraping abgefragt werden können. Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur eines Kontos« beschrieben.
  • Ein String mit einer Fehlermeldung.

Für jedes Konto muss mindestens die Kontonummer zurückgegeben werden, andernfalls wird das Konto ignoriert.

Aktualisierung eines Kontos

Mit dieser Funktion werden Saldo- und Umsatzinformationen oder der Wertpapierbestand eines Kontos abgefragt:

function RefreshAccount (account, since)

Parameter:

  1. Table account: Das Konto, das abgefragt werden soll. Die Strukur ist im Abschnitt »Datenstruktur eines Kontos« beschrieben.
  2. Number since: Der Buchungstag, ab dem Umsätze geliefert werden sollten. Das Skript braucht ältere Umsätze nicht mehr zu liefern. Die Angabe erfolgt in Form eines POSIX-Zeitstempels. Bei Depots wird anstelle dieses Parameters nil übergeben.

Mögliche Rückgabewerte:

  • Eine Tabelle mit ein oder mehreren Feldern:
    • Number balance: Kontostand
    • Array balances: Ein Array mit Tupeln (Kontostand, Währung). Dieses Feld sollte nur dann an Stelle von balance zurückgegeben werden, wenn das Konto mehrere Kontostände in unterschiedlichen Währungen besitzt.
    • Number pendingBalance: Summe der vorgemerkten Umsätze
    • Array transactions: Ein Array mit Umsätzen; Diese Umsätze werden als »neu« klassifiziert, wenn sie noch nicht in der Datenbank von MoneyMoney vorhanden sind. Andernfalls werden sie als Duplikate verworfen. Das Array sollte nach Buchungstag geordnet sein, mit den neuesten Umsätzen vorne. Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur eines Umsatzes« beschrieben.
    • Array securities: Ein Array mit Depotpositionen; Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur von Wertpapieren« beschrieben.
    • Number bonusPoints: Anzahl der Punkte in einem Bonusprogramm
  • Ein String mit einer Fehlermeldung.

Bei Depots wird nur das Feld securities erwartet, bei allen anderen Konten die Felder balance/balances und transactions. Wenn diese fehlen oder den Wert nil enthalten, wird in der GUI eine Fehlermeldung angezeigt, dass der Kontostand bzw. die Umsätze bzw. der Wertpapierbestand nicht abgefragt werden konnte.

Für jeden Umsatz müssen mindestens Betrag und Buchungstag angegeben werden, andernfalls führt dies ebenfalls zu einer Fehlermeldung.

Abmeldung

Diese Funktion führt den Abmeldevorgang durch:

function EndSession ()

Mögliche Rückgabewerte sind:

  • Nichts oder nil, wenn die Abmeldung erfolgreich war.
  • Ein String mit einer Fehlermeldung.

Vorlage

Folgende Vorlage kann als Ausgangspunkt für eigene Web Banking Extensions dienen.

WebBanking{version     = 1.00,
           url         = "https://moneymoney-app.com/onlinebanking",
           services    = {"Premium Account"},
           description = "Demo"}

function SupportsBank (protocol, bankCode)
  return protocol == ProtocolWebBanking and bankCode == "Premium Account"
end

function InitializeSession (protocol, bankCode, username, reserved, password)
  -- Login.
end

function ListAccounts (knownAccounts)
  -- Return array of accounts.
  local account = {
    name = "Premium Account",
    owner = "Jane Doe",
    accountNumber = "111222333444",
    bankCode = "80007777",
    currency = "EUR",
    type = AccountTypeGiro
  }
  return {account}
end

function RefreshAccount (account, since)
  -- Return balance and array of transactions.
  local transaction = {
    bookingDate = 1325764800,
    purpose = "Hello World!",
    amount = 42.00
  }
  return {balance=42.00, transactions={transaction}}
end

function EndSession ()
  -- Logout.
end

Tipp: Um während der Entwicklung einer Extension nicht bei jeder Skriptänderung die Kontoeinrichtung von MoneyMoney durchlaufen zu müssen, kann man ListAccounts wie in der Vorlage statische Informationen zurückgeben lassen. Wenn man dann erst einmal die Funktionen InitializeSession und EndSession implementiert hat, kann man sich in Ruhe den Funktionen ListAccounts und RefreshAccount widmen.

Tipp: In der Anfangsphase der Entwicklung einer Extension ist es gar nicht nötig, eine Online-Verbindung aufzubauen. Vorab mit einem Browser gespeicherte HTML-Seiten können über Lua-Funktionen geladen werden, so dass man gefahrlos mit dem Skript experimentieren kann.

Die API von MoneyMoney

Datenstruktur eines Kontos

Die Informationen eines Konto werden in einer Lua-Tabelle gespeichert. Folgende Felder können belegt werden, soweit deren Inhalt bekannt ist:

  • String name: Bezeichnung des Kontos
  • String owner: Name des Kontoinhabers
  • String accountNumber: Kontonummer
  • String subAccount: Unterkontomerkmal
  • Boolean portfolio: true für Depots und false für alle anderen Konten
  • String bankCode: Bankleitzahl
  • String currency: Kontowährung
  • String iban: IBAN
  • String bic: BIC
  • Konstante type: Kontoart; Mögliche Werte sind AccountTypeGiro (Girokonto), AccountTypeSavings (Sparkonto), AccountTypeFixedTermDeposit (Festgeldanlage), AccountTypeLoan (Darlehenskonto), AccountTypeCreditCard (Kreditkarte), AccountTypePortfolio (Wertpapierdepot), AccountTypeOther (Sonstige).

Datenstruktur eines Umsatzes

Die Daten eines Umsatzes werden in einer Lua-Tabelle gespeichert. Die Felder orientieren sich an SWIFT MT-940/MT-942 und können belegt werden, soweit deren Inhalt bekannt ist:

  • String name: Name des Auftraggebers/Zahlungsempfängers
  • String accountNumber: Kontonummer oder IBAN des Auftraggebers/Zahlungsempfängers
  • String bankCode: Bankzeitzahl oder BIC des Auftraggebers/Zahlungsempfängers
  • Number amount: Betrag
  • String currency: Währung
  • Number bookingDate: Buchungstag; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.
  • Number valueDate: Wertstellungsdatum; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.
  • String purpose: Verwendungszweck; Mehrere Zeilen können durch Zeilenumbrüche ("\n") getrennt werden.
  • Number transactionCode: Geschäftsvorfallcode
  • Number textKeyExtension: Textschlüsselergänzung
  • String purposeCode: SEPA-Verwendungsschlüssel
  • String bookingKey: SWIFT-Buchungsschlüssel
  • String bookingText: Umsatzart
  • String primanotaNumber: Primanota-Nummer
  • String batchReference: Sammlerreferenz
  • String endToEndReference: SEPA-Ende-zu-Ende-Referenz
  • String mandateReference: SEPA-Mandatsreferenz
  • String creditorId: SEPA-Gläubiger-ID
  • String returnReason: Rückgabegrund
  • Boolean booked: Gebuchter oder vorgemerkter Umsatz

Datenstruktur von Wertpapieren

Die Daten von Wertpapieren werden in einer Lua-Tabelle gespeichert. Die Felder orientieren sich an SWIFT MT-535/MT-571 und können belegt werden, soweit deren Inhalt bekannt ist:

  • String name: Bezeichnung des Wertpapiers
  • String isin: ISIN
  • String securityNumber: WKN
  • Number quantity: Nominalbetrag oder Stückzahl
  • String currencyOfQuantity: Währung bei Nominalbetrag oder nil bei Stückzahl
  • Number purchasePrice: Kaufpreis oder Kaufkurs
  • String currencyOfPurchasePrice: Von der Kontowährung abweichende Währung des Kaufpreises
  • Number exchangeRateOfPurchasePrice: Wechselkurs zum Kaufzeitpunkt
  • Number price: Aktueller Preis oder Kurs
  • String currencyOfPrice: Von der Kontowährung abweichende Währung des Preises
  • Number exchangeRateOfPrice: Aktueller Wechselkurs
  • Number amount: Wert der Depotposition in Kontowährung
  • Number originalAmount: Wert der Depotposition in Originalwährung
  • String currencyOfOriginalAmount: Originalwährung
  • String market: Name des Börsenplatzes
  • Number tradeTimestamp: Notierungszeitpunkt; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.

Objekt für eine HTTPS-Verbindung

connection = Connection()

Erzeugt ein Objekt, mit dem eine HTTPS-Verbindung zu einem Webserver aufgebaut werden kann.

content, charset, mimeType, filename, headers = connection:request(method, url[, postContent, postContentType, headers])

Diese Methode des Connection-Objekts fordert eine Ressource vom Webserver an.

Falls noch keine HTTPS-Verbindung zum Server besteht, wird diese aufgebaut. Das Connection-Objekt verwendet HTTP-Pipelining. Wenn der Server dies auch anbietet und solange über den URL-Parameter nicht der Server gewechselt wird, werden alle Anfragen über dieselbe HTTPS-Verbindung geschickt.

Für JSON-basierte REST-APIs sollte im Parameter headers das HTTP-Header-Feld Accept auf "application/json" gesetzt werden. Dann wird auch bei einem HTTP-Fehler die Serverantwort im Skript zurückgegeben. Andernfalls wird im Fehlerfall die Ausführung des Skripts abgebrochen und stattdessen in der GUI eine Fehlermeldung angezeigt.

Parameter:

  1. String method: HTTP-Request-Methode; Mögliche Werte sind "GET", "POST", "PUT", "PATCH" und "DELETE".
  2. String url: Server-URL; Die URL darf absolut oder relativ sein. Bei der ersten Server-Anfrage muss eine absolute URL angegeben werden. Relative URLs beziehen sich wie üblich auf die gerade aktive, d.h. zuletzt aufgerufene URL.
  3. Binary postContent: Die Daten, die mit einem HTTP-POST-Request an den Server gesendet werden sollen
  4. String postContentType: Der Inhalt des Felds Content-Type für den HTTP-POST-Header
  5. Dictionary headers: Weitere HTTP-Header-Felder

Rückgabewerte:

  1. Binary content: Daten vom Server
  2. String charset: Der Zeichensatz, mit dem die vom Server gelieferten Daten zu interpretieren sind
  3. String mimeType: MIME-Type der vom Server gelieferten Daten
  4. String filename: Dateiname aus dem HTTP-Header-Feld Content-Dispositon
  5. Dictionary headers: Vom Server gelieferte HTTP-Header-Felder

Zur Bestimmung des Zeichensatzes und des MIME-Typs werden der HTTP-Header des Servers und <meta>-Tags im HTML-Code herangezogen.

Beispiel:

content, charset, mimeType = connection:request("POST",
                                                "https://moneymoney-app.com/onlinebanking",
                                                "username=foo&password=bar",
                                                "application/x-www-form-urlencoded; charset=UTF-8")
print(content)   -- "<html>\n<head>\n<title>[…]"
print(charset)   -- "UTF-8"
print(mimeType)  -- "text/html"

Tipp: Die Art und Reihenfolge der Rückgabewerte ist so gewählt, dass sie sich für die Erzeugung eines HTML-Objektes verwenden lassen:

html = HTML(connection:request("GET", "https://moneymoney-app.com/onlinebanking"))

content, charset, mimeType = connection:get(url)

Kurzform für: connection:request("GET", url)

content, charset, mimeType = connection:post(url, postContent[, postContentType])

Kurzform für: connection:request("POST", url, postContent, postContentType)

connection:close()

Schließt die HTTPS-Verbindung zum Server. Normalerweise braucht diese Methode nicht aufgerufen werden, da nach der Ausführung des Skripts alle offenen Verbindungen automatisch geschlossen werden.

url = connection:getBaseURL()

Diese Methode gibt die zuletzt aufgerufene URL zurück.

Rückgabewert:

String url: Die zuletzt aufgerufene URL

connection:setCookie(cookie)

Jedes Skript erhält für die Dauer seiner Ausführung einen Speicher für HTTP-Cookies. Dieser Speicher wird von allen HTTP-Verbindungen, die innerhalb desselben Skripts aufgebaut werden, gemeinsam genutzt. Die Cookies werden automatisch aus dem HTTP-Header des Servers und den <meta>-Tags im HTML-Code extrahiert. Nach der Ausführung des Skripts werden alle Cookies wieder gelöscht.

Mit dieser Methode können dem Speicher weitere Cookies hinzugefügt oder vorhandene Cookies geändert werden.

Parameter:

String cookie: HTTP-Cookie; Das Format ist identisch zum Feld Set-Cookie im HTTP-Header.

Beispiel:

connection:setCookie("SESSION=foobar; path=/")

cookies = connection:getCookies()

Mit dieser Methode lassen sich die HTTP-Cookies abfragen, die für die gerade aktive, d.h. zuletzt aufgerufene URL gültig sind.

Rückgabewert:

String cookies: HTTP-Cookies; Das Format ist identisch zum Feld Cookies im HTTP-Header.

connection.useragent

Dieses Attribut vom Typ String enthält den Wert des Felds User-Agent für den HTTP-Header. Durch Veränderung dieses Werts lässt sich gegenüber dem Webserver ein bestimmter Browser oder ein mobiles Endgerät simulieren.

Beispiel:

connection.useragent = "Mozilla/5.0 (compatible; " .. MM.productName .. "/" .. MM.productVersion .. ")"

connection.language

Dieses Attribut vom Typ String enthält den Wert des Felds Accept-Language für den HTTP-Header. Bei manchen Servern lässt sich so die Sprache der Inhalte auswählen. Als Standardwert ist die Sprache des Betriebssystems voreingestellt.

Beispiel:

connection.language = "de-de"

Objekt für ein HTML-Dokument

html = HTML(content[, charset])

Erzeugt ein neues Objekt, mit dem sich in einem HTML-Dokument navigieren lässt.

Parameter:

  1. Binary content: HTML-Code
  2. String charset: Der Zeichensatz, mit dem der HTML-Code zu interpretieren ist. Wenn dieser Parameter fehlt, wird der Zeichensatz aus den <meta>-Tags extrahiert.

elements = html:xpath(query)

Wählt HTML-Elemente mittels eines XPath-Ausdrucks aus.

Parameter:

String query: XPath-Ausdruck in der XML Path Language Version 1.0; Alle Tag- und Attributsnamen müssen klein geschrieben werden.

Rückgabewert:

Objekt elements: Eine Liste von HTML-Elementen, die durch den XPath-Ausdruck ausgewählt wurden. Die Methoden, die auf dieses Objekt angewendet werden können, sind im Abschnitt »Objekt für HTML-Elemente« beschrieben.

Tipp: Die Entwicklertools von Webbrowsern bieten komfortable Werkzeuge an, um XPath-Ausdrücke zu schreiben und zu testen.

text = html:html()

Diese Methode generiert aus dem HTML-Dokument neuen, formatierten HTML-Code. Dieser ist nicht unbedingt identisch zum ursprünglichen HTML-Code. Der generierte HTML-Code ist immer UTF-8-kodiert.

Rückgabewert:

String text: HTML-Code


Objekt für HTML-Elemente

count = elements:length()

Diese Methode liefert die Anzahl der HTML-Elemente, die sich im Objekt elements befinden.

Rückgabewert:

Number count: Anzahl der HTML-Elemente

elements = elements:get(n)

Diese Methode wählt das n-te HTML-Element aus elements aus.

Parameter:

Number n: Index des auszuwählenden HTML-Elements; Wie in Lua üblich, beginnt die Indexierung bei 1.

Rückgabewert:

Objekt elements: Der Rückgabewert besteht selbst wieder aus einem Objekt für HTML-Elemente. Wenn n ein gültiger Index ist, enthält elements das n-te HTML-Element. Andernfalls ist elements leer.

Beispiel:

if elements:get(2):length() == 1 then print "Fnord!" end

elements:each(function (index, element))

Diese Methode durchläuft alle HTML-Elemente von elemente und führt für jedes HTML-Element eine Aktion aus.

Parameter:

Function function (index, element): Eine Funktion, die für jedes HTML-Element ausgeführt werden soll. Die Funktion besitzt selbst zwei Parameter:

  1. Number index: Index des aktuellen HTML-Elements; Wie in Lua üblich, beginnt die Indexierung bei 1.
  2. Object element: Dieser Parameter besteht selbst wieder aus einem Objekt für HTML-Elemente und enthält genau ein HTML-Element.

Wenn die Funktion func den Wert false zurückgibt, wird die Methode each abgebrochen.

Beispiel:

elements:each(function (index, element))
  print (index .. "=" .. element:text())
end

elements = elements:reverse()

Diese Methode dreht die Reihenfolge der HTML-Elemente von elemente um.

Rückgabewert:

Objekt elements: Der Rückgabewert besteht selbst wieder aus einem Objekt für HTML-Elemente, welches die HTML-Elemente in umgekehrter Reihenfolge enthält.

elements = elements:children()

Diese Methode wählt die unmittelbaren Kindelemente der HTML-Elemente aus elements aus.

Rückgabewert:

Objekt elements: Der Rückgabewert besteht selbst wieder aus einem Objekt für HTML-Elemente und enthält die HTML-Kindelemente.

elements = elements:xpath(query)

Diese Methode wählt mittels eines XPath-Ausdrucks HTML-Elemente relativ zum ersten HTML-Element von elements aus. Der XPath-Ausdruck query muss dazu ebenfalls relativ sein, d.h. mit einem Punkt beginnen.

Parameter:

String query: Relativer XPath-Ausdruck (beginnend mit einem Punkt) in der XML Path Language Version 1.0; Alle Tag- und Attributsnamen müssen klein geschrieben werden.

Rückgabewert:

Objekt elements: Eine Liste von HTML-Elementen, die durch den XPath-Ausdruck ausgewählt wurden.

text = elements:text()

Diese Methode liefert den kombinierten Text, der sich zwischen den HTML-Tags der HTML-Elemente elements und deren Kindelementen befindet.

Rückgabewert:

String text: Text, der sich zwischen den HTML-Tags befindet.

value = elements:attr(attribute)

Diese Methode gibt den Inhalt eines Attributs des ersten HTML-Elements aus elements zurück.

Parameter:

String attribute: Name des Attributs

Rückgabewert:

String value: Inhalt des Attributs

elements:attr(attribute, value)

Diese Methode ändert ein Attribut für alle HTML-Elements aus elements.

Parameter:

  1. String attribute: Name des Attributs
  2. String value: Neuer Inhalt des Attributs

value = elements:val()

Diese Methode gibt den Wert eines Formularfelds zurück. Das erste HTML-Element in elements muss ein Formularfeld sein. Im Gegensatz zur Methode elements:attr("value") berücksichtigt diese Methode auch das Attribut disabled und wertet die ausgewählte Option von Auswahllisten (<select>-Tag) aus.

Rückgabewert:

String value: Wert des Formularfelds

elements:select(value)

Diese Methode wählt eine Option in einer Auswahlliste (<select>-Tag) aus. Das erste HTML-Element in elements muss eine Auswahlliste sein. Im Gegensatz zur Methode elements:attr("selected", "selected") berücksichtigt diese Methode auch das Attribut disabled und wählt die übrigen Optionen ab.

Parameter:

String value: Ausgewählte Option

method, url[, postContent, postContentType] = elements:click()

Diese Methode erzeugt aus einem HTML-Link oder einem HTML-Formular die Parameter für einen HTTP-Request. In elements muss als erstes HTML-Element ein Link (<a href>-Tag) oder ein Submit-Button (<input type="submit">-Tag, <button>-Tag) oder ein Image-Button (<input type="image">-Tag) vorhanden sein.

Bei einem HTML-Link wird die verlinkte URL zurückgegeben. Bei einem Formular werden die Werte der <input>-Tags URL-kodiert und entweder als GET-Parameter an die URL angehängt oder als POST-Parameter zurückgegeben.

Rückgabewerte:

  1. String method: HTTP-Request-Methode; Mögliche Werte sind "GET" und "POST".
  2. String url: Server-URL
  3. Binary postContent: Die Daten, die mit einem HTTP-POST-Request an den Server gesendet werden sollen.
  4. String postContentType: Der Inhalt des Felds Content-Type für den HTTP-POST-Header.

Tipp: Die Art und Reihenfolge der Rückgabewerte ist so gewählt, dass sie sich für einen HTTP-Request verwenden lassen:

connection:request(elements:click())

method, url[, postContent, postContentType] = elements:submit()

Diese Methode erzeugt aus einem HTML-Formular ohne Submit-Button die Parameter für einen HTTP-Request. In elements muss als erstes HTML-Element ein Formular (<form>-Tag) vorhanden sein. Die Werte der <input>-Tags werden URL-kodiert und entweder als GET-Parameter an die URL angehängt oder als POST-Parameter zurückgegeben. Die Werte von Submit-Buttons (<input type="submit">-Tag) werden ignoriert, da das Formular ohne Submit-Button generiert wird.

Rückgabewerte:

  1. String method: HTTP-Request-Methode; Mögliche Werte sind "GET" und "POST".
  2. String url: Server-URL
  3. Binary postContent: Die Daten, die mit einem HTTP-POST-Request an den Server gesendet werden sollen.
  4. String postContentType: Der Inhalt des Felds Content-Type für den HTTP-POST-Header.

Tipp: Die Art und Reihenfolge der Rückgabewerte ist so gewählt, dass sie sich für einen HTTP-Request verwenden lassen:

connection:request(elements:submit())

Objekt für ein JSON-Dokument

fields = JSON(json):dictionary()

Diese Methode konvertiert ein JSON-Dokument in eine Lua-Datenstruktur.

Parameter:

Binary json: JSON-Dokument

Rückgabewert:

Dictionary oder Array fields: Lua-Datenstruktur des JSON-Dokuments

lua = JSON():set(fields):json()

Diese Methode konvertiert eine Lua-Datenstruktur zunächst in ein JSON-Dokument.

Parameter:

Dictionary oder Array fields: Lua-Datenstruktur des JSON-Dokuments

Rückgabewert:

Binary json: JSON-Dokument


Objekt für ein PDF-Dokument

text = PDF(pdf):text()

Diese Methode extrahiert, so gut wie möglich, den unformattierten Text aus einem PDF-Dokument.

Parameter:

Binary pdf: PDF-Dokument

Rückgabewert:

String text: Unformattierter Text


Objekt für Bankinformationen

bankInfo = BankInfo(bankCode)

Erzeugt ein neues Objekt mit Informationen zu einer Bank.

Parameter:

String bankCode: Bankleitzahl

Beispiel:

print(BankInfo("80007777").name)

Datenstruktur für Bankinformationen

Die Informationen zu einer Bank werden in einer Lua-Tabelle gespeichert. Derzeit gibt es nur ein einziges belegtes Feld:

  • String name: Name der Bank

Sonstige Funktionen

str = MM.localizeText(str)

Mit dieser Funktion kann ein Text übersetzt werden. Diese Funktion ist primär für die mit MoneyMoney ausgelieferten Extensions gedacht. Sie ist ein Wrapper für die Cocoa-Funktion NSLocalizedString und liefert natürlich nur dann eine Übersetzung, wenn der Text in MoneyMoney hinterlegt worden ist.

Parameter:

String str: Englischer Text

Rückgabewert:

String str: Übersetzter Text

str = MM.localizeDate([format, ]date)

Lokalisiert eine Zeitangabe. Da die von Lua unterstützten POSIX Locales innerhalb von macOS-Apps nicht zur Verfügung stehen, baut diese Funktion auf der Cocoa-Klasse NSDateFormatter auf.

Parameter:

  1. String format (optional): Ausgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSDateFormatter nach dem Unicode Technical Standard #35.
  2. Number date: Datum; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.

Rückgabewert:

String str: Datum im lokalisierten Format

str = MM.localizeNumber([format, ]num)

Lokalisiert eine Zahl. Da die von Lua unterstützten POSIX Locales innerhalb von macOS-Apps nicht zur Verfügung stehen, baut diese Funktion auf der Cocoa-Klasse NSNumberFormatter auf.

Parameter:

  1. String format (optional): Ausgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSNumberFormatter nach dem Unicode Technical Standard #35.
  2. Number num: Zahl

Rückgabewert:

String str: Zahl im lokalisierten Format

str = MM.localizeAmount([format, ]amount[, currency])

Lokalisiert einen Währungsbetrag.

Parameter:

  1. String format (optional): Ausgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSNumberFormatter nach dem Unicode Technical Standard #35.
  2. Number amount: Betrag
  3. String currency (optional): Währung; Ohne diesen Parameter wird nur der Betrag ohne Währungsangabe zurückgegeben.

Rückgabewert:

String str: Währungsbetrag im lokalisierten Format

urlencoded = MM.urlencode(str, [charset])

Wendet eine URL-Kodierung an.

Parameter:

  1. String str: Zu kodierender Text
  2. String charset (optional): Zeichensatz; Die Angabe erfolgt wie bei HTTP nach IANA. Ohne diesen Parameter wird ISO-8859-1 verwendet.

Rückgabewert:

String urlencoded: URL-kodierter Text.

str = MM.urldecode(urlencoded)

Entfernt die URL-Kodierung.

Parameter:

String urlencoded: URL-kodierter Text.

Rückgabewert:

String str: Text ohne URL-Kodierung.

data = MM.toEncoding(charset, str[, bom])

Konvertiert einen Text von UTF-8 zu einem anderen Zeichensatz.

Parameter:

  1. String charset: Zeichensatz; Die Angabe erfolgt wie bei HTTP nach IANA.
  2. String str: Text in UTF-8
  3. Boolean bom (optional): Wenn dieser Parameter mit true belegt ist, wird der Rückgabewert um eine Byte Order Mark (BOM) ergänzt, sofern sie für den angegeben Zeichensatz existiert.

Rückgabewert:

Binary data: Text im angegebenen Zeichensatz

str = MM.fromEncoding(charset, data)

Konvertiert einen Text von einem anderen Zeichensatz zu UTF-8.

Parameter:

  1. String charset: Zeichensatz; Die Angabe erfolgt wie bei HTTP nach IANA.
  2. Binary data: Text im angegebenen Zeichensatz

Rückgabewert:

String str: Text in UTF-8

encoded = MM.base64(data)

Konvertiert Daten zu Base64.

Parameter:

Binary data: Zu konvertierende Daten

Rückgabewert:

String encoded: Base64-kodierte Daten

data = MM.base64decode(encoded)

Konvertiert Daten von Base64.

Parameter:

Binary encoded: Base64-kodierte Daten

Rückgabewert:

String data: konvertierte Daten

digest = MM.sha512(data)
digest = MM.sha256(data)
digest = MM.sha1(data)
digest = MM.md5(data)

Berechnet einen SHA512-, SHA256-, SHA1- oder MD5-Hashwert.

Parameter:

Binary data: Daten, über die der Hashwert berechnet werden soll.

Rückgabewert:

String digest: Hashwert als hexidezimaler String

digest = MM.hmac512(key, data)
digest = MM.hmac384(key, data)
digest = MM.hmac256(key, data)
digest = MM.hmac1(key, data)

Berechnet einen HMAC512-, HMAC384-, HMAC256- oder HMAC1-Message-Authentication-Code.

Parameter:

  1. Binary key: HMAC-Schlüssel
  2. Binary data: Daten, über die der Message Authentication Code berechnet werden soll.

Rückgabewert:

Binary digest: Message Authentication Code als binärer String

timestamp = MM.time()

Gibt die aktuelle Uhrzeit zurück. Im Gegensatz zum Aufruf os.time() enthält der Rückgabewert auch Millisekunden als Nachkommestellen.

Rückgabewert:

Number timestamp: Aktuelle Uhrzeit in Form eines POSIX-Zeitstempels.

MM.sleep(seconds)

Unterbricht die Ausführung des Skripts für ein paar Sekunden.

Parameter:

Number seconds: Anzahl der Sekunden

MM.printStatus(...)

Diese Funktion arbeitet ähnlich zur Lua-Funktion print: Die Parameter werden mittels der Lua-Funktion tostring zu einem String konvertiert und im Protokoll-Fenster von MoneyMoney angezeigt. Zusätzlich wird der String als Statusmeldung in der GUI angezeigt.