Code Monkey home page Code Monkey logo

dkb-robo's Introduction

dkb-robo

GitHub release GitHub last commit (branch) GitHub last commit (branch)

Codecov main Codecov devel

Security Rating Maintainability Rating Reliability Rating Quality Gate Status

dkb-robo is a python library to access the internet banking area of "Deutsche Kreditbank" to fetch

  • account information and current balances
  • transactions from creditcards and checking accounts (Girokonten)
  • query the content of "DKB Postbox"
  • get standing orders (Dauerauftrag)
  • get information about credit limits and exemption orders (Freistellungsauftrag)

Starting from version 0.9 dkb-robo can handle the 2nd factor DKB introduced to fulfill the PSD2 obligations. Starting from September 2019 logins must be confirmed by either

The introduction of a 2nd factor does limit the usage of dkb-robo for automation purposes. DKB is unfortunately not willing/ not able not allowed to open their PSD2-API for non-Fintechs. I discussed this with them for weeks at some point they stopped responding to my emails so I gave up.

DKB introduced a new web-frontend in July 2023 which is using a REST-API as backend. The migration to the new REST endpoints started with v0.22, will take a certain amount of time and gets spread across different releases. We are trying to keep backwards compatibility as much as we can. However, there are certain breaking changes you need to be aware when upgrading from a release prior to v0.22. Migration status and a list of breaking changes can be found in the issue section of this repo.

Getting Started

These instructions will get you a copy of the project up and running on your local machine.

Prerequisites

To run dkb-robo on your system you need

Please make sure python and all the above modules had been installed successfully before you start any kind of testing.

Installing

via Pypi

> pip install dkb_robo

manually for all users

  1. download the archive and unpack it
  2. enter the directory and run the setup script
> python setup.py install

manually for a single user

  1. download the archive and unpack it
  2. move the "dkb_robo" subfolder into the directory your script is located

SBOM

A bill of material of the packages coming along wiht dkb-robo will be automatically created during build process and stored in my SBOM respository

Usage

you need to import dkb-robo into your script

> from dkb_robo import DKBRobo

create a new DKBRobo context handler and login to DKB portal

> with DKBRobo(dkb_user=<login username>, dkb_password=<password>, tan_insert=True|False, legacy_login=True|False, mfa_device=<m|int>, debug=True|False) as dkb:
  • dbk_user: username to access the dkb portal
  • dkb_password: corresponding login password
  • tan_insert: (True/False) TAN usage - dbk-robo will ask for a TAN (generated by either ChipTan or TAN2go) during login
  • legacy_login: (True/False) optional - set to "True" to use the legacy DKB banking page
  • mfa_device: ('m'/Integer) optional (not supported in legacy mode) - preselect MFA device to be used for 2nd factor - 'm' - main device, otherwise number from device-list
  • debug: (True/False) Debug mode

After login you can return the

  • the last login date
print(dkb.last_login)
14.03.2019, 13:19 Uhr
  • a dictionary containing a list of your accounts, the actual balance and a link to fetch the transactions
from pprint import pprint
pprint(dkb.account_dic)
{0: {
     'amount': '1458.00',
     'currencycode': 'EUR',
     'date': '22.01.2023',
     'holdername': 'Firstname Lastname',
     'iban': 'DEXXXXXXXXXXXXXXXXXXXXX',
     'id': 'xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
     'limit': '2500.00',
     'name': 'Girokonto',
     'productgroup': 'Meine Konten',
     'transactions': 'https://banking.dkb.de/api/accounts/accounts/xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/transactions',
     'type': 'account'},
 1: {
     'amount': -1000.23,
     'currencycode': 'EUR',
     'date': '22.01.2023',
     'holdername': 'Firstname Lastname',
     'id': 'xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
     'limit': '2000.00',
     'maskedpan': '1234XXXXXXXX5678',
     'name': 'Visa CC',
     'productgroup': 'Meine Konten',
     'transactions': 'https://banking.dkb.de/api/credit-card/cards/xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/transactions',
     'type': 'creditcard'},
 2: {
     'amount': 100000.23,
     'currencycode': 'EUR',
     'date': '22.01.2023',
     'holdername': 'Firstname lastname',
     'id': 'xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
     'limit': '0.00',
     'maskedpan': '5678XXXXXXXX1234',
     'name': 'Another Visa',
     'productgroup': 'Meine Konten',
     'transactions': 'https://banking.dkb.de/api/credit-card/xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/transactions',
     'type': 'creditcard'},
 3: {
     'amount': '123456,79',
     'currencycode': 'EUR',
     'holdername': 'Firstname Lastname',
     'id': 'xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
     'name': 'Mein Depot',
     'productgroup': 'Meine Konten',
     'transactions': 'https://banking.dkb.de/api/broker/brokerage-accounts/xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx(positions?include=instrument%2Cquote',
     'type': 'depot'}}

to get the list of transactions for a certain checking account or a credit card use the following method

tlist = dkb.get_transactions(link, type, date_from, date_to)
  • link - link to get transactions for a specific account - see former step if you do not know how to get it
  • type - account type (either "account" or "creditcard") - see former step if you do not know how to get it
  • date_from - start date in European notation (DD.MM.YYYY)
  • date_to - end date in European notation (DD.MM.YYYY)
  • transaction_type - optional: "booked" (default if not specified) or "pending" ("vorgemerkt")

this method returns a list of transactions.

A list of transactions for a regular checking account follows the below format.

from pprint import pprint
pprint(tlist)
[{'amount': -44.98,
  'bdate': '2023-01-22',
  'currencycode': 'EUR',
  'customerreferenz': 'XXXXXX',
  'peer': 'PayPal Europe S.a.r.l. et Cie S.C.A',
  'peeraccount': 'XXXXXXXXX',
  'peerbic': 'XXXXXXXXX',
  'peerid': 'XXXXXXXXXXX',
  'postingtext': 'FOLGELASTSCHRIFT',
  'reasonforpayment': 'XXXXXX PP.XXXXX.PP . Foo-bar AG, Ihr Einkauf bei '
                      'Foo-bar AG',
  'vdate': '2023-01-22'},
 {'amount': -70.05,
  'bdate': '2023-01-22',
  'currencycode': 'EUR',
  'customerreferenz': '68251782022947180823144926',
  'peer': 'FEFASE GmbH',
  'peeraccount': 'XXXXXXXXX',
  'peerbic': 'XXXXXXXXX',
  'peerid': 'XXXXXXXXX',
  'postingtext': 'SEPA-ELV-LASTSCHRIFT',
  'reasonforpayment': 'ELV68251782 18.08 14.49 MEFAS ',
  'vdate': '2023-01-22'},
 {'amount': -7.49,
  'bdate': '2023-01-22',
  'currencycode': 'EUR',
  'customerreferenz': '3REFeSERENC',
  'peer': 'PEER',
  'peeraccount': 'XXXXXXXXX',
  'peerbic': 'XXXXXXXXX',
  'peerid': 'XXXXXXXXX',
  'postingtext': 'FOLGELASTSCHRIFT',
  'reasonforpayment': 'VIELEN DANK VON BAR-FOO GMBH',
  'vdate': '2023-01-22'}]

The list of transactions from a creditcard will look as below:

[{'amount': 500.0,
  'bdate': '2023-08-18',
  'currencycode': 'EUR',
  'text': 'Berliner Sparkasse',
  'vdate': '2023-08-18'},
 {'amount': 125.95,
  'bdate': '2023-08-14',
  'currencycode': 'EUR',
  'text': 'Zara Deutschland 3742',
  'vdate': '2023-08-14'},
 {'amount': 500.0,
  'bdate': '2023-08-14',
  'currencycode': 'EUR',
  'text': 'Commerzbank Berlin',
  'vdate': '2023-08-14'}]

A brokerage account (depot) will not show the list of transactions but rather a list of positions:

[{'currencycode': 'EUR',
  'isin_wkn': 'DE0005140008',
  'lastorderdate': '2017-01-01',
  'market': 'Frankfurt',
  'price': 9.872,
  'price_euro': '39488.00',
  'quantity': 4000.0,
  'shares_unit': 'pieces',
  'text': 'DEUTSCHE BANK AG NA O.N.'},
 {'currencycode': 'EUR',
  'isin_wkn': 'DE0005557508',
  'lastorderdate': '2017-10-01',
  'market': 'Frankfurt',
  'price': 19.108,
  'price_euro': '28.662.00',
  'quantity': 1500.0,
  'shares_unit': 'pieces',
  'text': 'DT.TELEKOM AG NA'}]

to get the credit limits per account or credit-card the method get_credit_limits() must be used

> c_list = dkb.get_credit_limits()

This method returns a dictionary of all identified accounts including the credit limit per account

{u'XXXX********XXXX': 100.00,
 u'4748********XXXX': 10000.00,
 u'XXXX********XXXX': 10000.00,
 u'DEXX XXXX XXXX XXXX XXXX XX': 200.00,
 u'DEXX XXXX XXXX XXXX XXXX XX': 2000.00}

A list of standing orders (Daueraufträge) can be obtained by calling get_standing_orders() method

> so = dkb.get_standing_orders(account_id)
  • account_id - 'id' field from account dictionary (dkb.account_dic[x]['id'])

A list of standing orders will be returned containing a dictionary per standing order

> pprint(so)
[{'amount': 30.0,
  'creditoraccount': {'bic': 'BIC-1', 'iban': 'IBAN-1'},
  'currencycode': 'EUR',
  'interval': {'frequency': 'monthly',
               'from': '2019-01-05',
               'holidayExecutionStrategy': 'following',
               'nextExecutionAt': '2023-10-01',
               'until': '2025-12-01'},
  'purpose': 'Purpose-1',
  'recpipient': 'Recipient-1'},
 {'amount': 58.0,
  'creditoraccount': {'bic': 'BIC-2', 'iban': 'IBAN-2'},
  'currencycode': 'EUR',
  'interval': {'frequency': 'monthly',
               'from': '2022-12-30',
               'holidayExecutionStrategy': 'following',
               'nextExecutionAt': '2023-12-01'},
  'purpose': 'Purpose-2',
  'recpipient': 'Recipient-2'},]

The method get_exemption_order() can be used to get the exemption orders (Freistellungsaufträge)

> exo = dkb.get_exemption_order()

A dictionary similar to the one below will be returned

> pprint(exo)
{1: {'amount': 1602.0,
     'available': 1602.0,
     'description': u'Gemeinsam mit XXXX XXXX',
     'used': 0.0,
     'validity': u'01.01.2017  unbefristet'}}

To get the amount of dkb points the below method can be used

> points_dic = dkb.get_points()

A dictionary similar to the below will be returned

> pprint(points_dic)
{u'DKB-Punkte': 99999,
 u'davon verfallen zum  31.12.2018': 999}

To scan the DKB postbox for documents the below method can be used

> document_dic = dkb.scan_postbox(path, download_all, archive, prepend_date)
  • path - optional argument. If specified, documents will be downloaded and stored
  • dowload_all (True/False) - optional argument. By default only unread documents from DKB postbox will get downloaded and marked as "read". By setting this parameter all documents will be downloaded
  • archive (True/False) - optional argument. When set to True the "Archiv" folder in the Postbox will be scanned and documents will be downloaded if a path variable is specificed. Handle this parameter with care as the amount of documents to be downloaded can be huge.
  • prepend_date (True/False) - optional argument. Prepend document date in YYYY-MM-DD_ format to each document to allow easy sorting of downloaded files

The method will return a dictionary containing the different postbox folders and links to download the corresponding documents

Check the scripts dkb_example.py and dkb_docdownload.py for further examples.

dkb_robo command line interface (CLI)

Starting with v0.20 dkb_robo comes with a CLI tool

$ dkb --help
Usage: dkb [OPTIONS] COMMAND [ARGS]...

Options:
  -d, --debug                     Show additional debugging
  -t, --use-tan                   dbk-robo will ask for a TAN (generated by
                                  either ChipTan or TAN2go) during login
  -u, --username TEXT             username to access the dkb portal
                                  [required]
  -p, --password TEXT             corresponding login password
  --format [pprint|table|csv|json]
                                  output format to use
  --help                          Show this message and exit.

Commands:
  accounts
  credit-limits
  last-login
  standing-orders
  transactions

Example command to fetch account list

py dkb -u <user> -p <password> accounts

Example commands to fetch transactions via CLI tool

py dkb -u <user> -p <password> transactions --name Girokonto
py dkb -u <user> -p <password> transactions --account "DE75xxxxxxxxxxxxxxxxxxx"
py dkb -u <user> -p <password> transactions --account "DE75xxxxxxxxxxxxxxxxxxx" --date-from 2023-08-01  --date-to 2023-08-15"

Further documentation

please check the doc folder of the project. You will find further documentation and an example scripts of all dkb-robo methods there.

Contributing

Please read CONTRIBUTING.md for details on my code of conduct, and the process for submitting pull requests. Please note that I have a life besides programming. Thus, expect a delay in answering.

Versioning

I use SemVer for versioning. For the versions available, see the tags on this repository.

License

This project is licensed under the GPLv3 - see the LICENSE.md file for details

dkb-robo's People

Contributors

bam8i avatar carlambroselli avatar dominikrob avatar flammermann avatar grindsa avatar jusjusjus avatar rwilhelm avatar scompt avatar tbm avatar wngr avatar wonko21 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dkb-robo's Issues

Checking account classification failes since 23.07.2020

Checking account classification failes as DKB removed the "Cash im Shop" link in account overview. As result get_transactions() failes with the below error

    TRANSACTION_DIC[1] = dkb.get_transactions(dkb.account_dic[0]['transactions'], dkb.account_dic[0]['type'], YESTERDAY, TODAY)
  File "/usr/lib/python2.7/site-packages/dkb_robo/dkb_robo.py", line 430, in get_transactions
    transaction_list = self.get_creditcard_transactions(transaction_url, date_from, date_to)
  File "/usr/lib/python2.7/site-packages/dkb_robo/dkb_robo.py", line 107, in get_creditcard_transactions
    self.dkb_br.select_form('#form1579108072_1')
  File "/usr/lib/python2.7/site-packages/mechanicalsoup/stateful_browser.py", line 207, in select_form
    raise LinkNotFoundError()
mechanicalsoup.utils.LinkNotFoundError

migration to the new DKB frontend

migration status

  • DKBRobo.account_dic() - ✅ - released with 0.23
  • DKBRobo.get_credit_limits() - ✅ - released with 0.25
  • DKBRobo.get_exemption_order()- ❌
  • DKBRobo.get_points() - ❌
  • DKBRobo.get_standing_orders()) - ✅ - released with 0.25
  • DKBRobo.get_transactions()-:white_check_mark: - released with 0.23
  • DKBRobo.last_login- ❌
  • DKBRobo.login() - ✅ - released with 0.22
  • DKBRobo.scan_postbox - ✅ - released with 0.25

breaking changes when migrating to the new frontend:

I am trying to ensure a certain level of backwards compatibility however there are a few changes you need to be aware when migrating to the new frontend.

general

  • default date format is changed to %Y-%m-%d

DKBRobo.account_dic()

  • account ordering is based on the new frontend
  • debit cards are shown in overview
  • IBANs are now represented without spaces
  • card numbers are masked
  • product groups (taken from UI) are shown in account overview
  • additional account attributes (currency code, limit)
  • additional card attributes (holder-name, status, expiry date)

DKBRobo.get_standing_orders()

  • account_dic[x]['id'] must be specified as input
  • data-structure changed (interval subtree added)

DKBRobo.get_transactions()

  • "mandatreferenz" and "customerreferenz" attributes will only be shown if available

DKBRobo.scan_postbox()

  • the document list provided in via API larger than shown in UI
  • so far only documents from categories "Kontoauszüge" and "Kreditabrechnungen" provided via API

Provide ability to download CSV

As a workaround to #10 it would be sufficient for me as a user to be able to programmatically download the CSV (upper right corner of the page ($event=csvExport), after selecting the from_date and to_date. The CSV contains the full information for the account.

TypeError when trying to log in

hey nice project! When I try to log in

with DKBRobo(DKB_USER, DKB_PASSWORD) as dkb:
    print(dkb.last_login)

I get the following error

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-a1ff75b89985> in <module>
      1 DKB = DKBRobo(dkb_user=DKB_USER, dkb_password=DKB_PASSWORD)
----> 2 DKB.login()
      3 DKB.account_dic

~/.miniconda/envs/banking/lib/python3.7/site-packages/dkb_robo/dkb_robo.py in login(self)
    386 
    387             # parse account date
--> 388             self.account_dic = self.parse_overview(soup)
    389 
    390 

~/.miniconda/envs/banking/lib/python3.7/site-packages/dkb_robo/dkb_robo.py in parse_overview(self, soup)
    578                     overview_dic[counter]['type'] = 'depot'
    579                     link = cols[4 + ontop].find('a', attrs={'class':'evt-depot'})
--> 580                     overview_dic[counter]['transactions'] = self.base_url + link['href']
    581                 except IndexError:
    582                     pass

TypeError: 'NoneType' object is not subscriptable

Maybe that's due to the link variable not being filled, but I did not really dig into it.

Question regarding startdate and entdate

Hi,

I have a question regarding this part from the documentation:

date_from - start date in European notation (DD.MM.YYYY)
date_to - end date in European notation (DD.MM.YYYY)

=> Are these related used for the the column bdate or vdate?

Thanks for clarification.
Christian

scan_documents with path and downloading all from archive fails for most documents

Some douments get fetched, but for most the debug output is:

_download_document()

DKBRobo._get_document(https://www.dkb.de/DkbTransactionBanking/content/mailbox/MessageList.xhtml?$event=getMailboxAttachment&filename=Kontoauszug+Nr.+062_2020+zu+Konto+1234567890&row=136)

https://www.dkb.de:443 "GET /DkbTransactionBanking/content/mailbox/MessageList.xhtml?$event=getMailboxAttachment&filename=Kontoauszug+Nr.+062_2020+zu+Konto+1234567890&row=136 HTTP/1.1" 655 None

Any clue?

Thanks
Florian

Have a CI

Lets automate testing!

After some tests are done (see #2 ) put them in a ci (eg on a gitlab ) and let them run on each commit.

Some Unit Tests

Hi lets write some unit tests. I might find some time later this week or on the weekend

Display full transaction information

When querying transactions and getting them as a list, only the abbreviated text is returned. It would be helpful to provide the possibility to query the extended information (the stuff you get when clicking the magnifier symbol next to it in the web interface).

Code refactoring for easier audit

Description:
In the process of reviewing the monolithic Python code, I encountered unnecessary complexity that hindered the understanding of the code.

Proposed Changes:

  1. Code Modularization: Split code into separate files. Uppon my uderstanding a split into the legacy API, new API, and utility functions would be a good first step.

  2. Type Hints: Introduce type hints for function headers.

Benefits:

  • Improved Auditability: Easier review of specific components for enhanced security.

  • Enhanced Readability: Improved overall readability and maintainability.

  • Type Safety: Clearer documentation of expected input/output types.

PS:
Thank you for creating and maintaining this library. I'm grateful for the existence of such a helpful tool. Your work is highly appreciated!

Getting accounts list with CLI fails both in legacy and non-legacy login

I'm on version v0.23 and get the following error when using legacy login:

$ python3 dkb --debug -u xxxxxx -p xxxx --use-tan accounts 
DKBRobo._login()

DKBRobo._new_instance()

Starting new HTTPS connection (1): www.ib.dkb.de:443
https://www.ib.dkb.de:443 "GET /banking HTTP/1.1" 200 None
https://www.ib.dkb.de:443 "POST /banking HTTP/1.1" 200 None
DKBRobo._ctan_check()

Login failed: LinkNotFoundError

When using the non-legacy login, I get the following error:

$ python3 dkb --debug -u xxxxx -p xxxxx --use-tan accounts 
DKBRobo._login()

DKBRobo._new_session()

Starting new HTTPS connection (1): banking.dkb.de:443
https://banking.dkb.de:443 "GET /login HTTP/1.1" 200 None
DKBRobo._get_token()

https://banking.dkb.de:443 "POST /api/token HTTP/1.1" 200 None
DKBRobo._get_mfa_methods()

https://banking.dkb.de:443 "GET /api/mfa/mfa/methods?filter%5BmethodType%5D=seal_one HTTP/1.1" 200 None
_select_mfa_device()

Pick an authentication device from the below list:
[0] - DKB-App on XXXXX
[1] - DKB-App on XXXXX
[2] - DKB-App on XXXXX
:0
DKBRobo._process_userinput(0)
_select_mfa_device() ended with: 0
DKBRobo._get_mfa_challenge_id() login with device_num: 0

DKBRobo._get_mfa_challenge_id(): devicename: DKB-App on Google Pixel 4

https://banking.dkb.de:443 "POST /api/mfa/mfa/challenges HTTP/1.1" 201 None
DKBRobo._process_challenge_response()

DKBRobo._complete_2fa()

DKBRobo._print_2fa_confirmation()

check your banking app on "DKB-App on Google Pixel 4" and confirm login...
https://banking.dkb.de:443 "GET /api/mfa/mfa/challenges/xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx HTTP/1.1" 200 None
DKBRobo._check_processing_status()

DKBRobo._login: cnt 1 got processing flag
https://banking.dkb.de:443 "GET /api/mfa/mfa/challenges/xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx HTTP/1.1" 200 None
DKBRobo._check_processing_status()

DKBRobo._login: cnt 2 got processing flag
https://banking.dkb.de:443 "GET /api/mfa/mfa/challenges/xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx HTTP/1.1" 200 None
DKBRobo._check_processing_status()

DKBRobo._login: cnt 3 got processed flag
DKBRobo._update_token()

https://banking.dkb.de:443 "POST /api/token HTTP/1.1" 200 None
DKBRobo.get_portfolio()

https://banking.dkb.de:443 "GET /api/terms-consent/consent-requests??filter%5Bportfolio%5D=DKB HTTP/1.1" 400 None
https://banking.dkb.de:443 "GET /api/config/users/me/product-display-settings HTTP/1.1" 200 None
DKBRobo._get_accounts()

https://banking.dkb.de:443 "GET /api/accounts/accounts HTTP/1.1" 200 None
DKBRobo._get_cards()

https://banking.dkb.de:443 "GET /api/credit-card/cards?filter%5Btype%5D=creditCard&filter%5Bportfolio%5D=dkb&filter%5Btype%5D=debitCard HTTP/1.1" 200 None
DKBRobo._get_brokerage_accounts()

https://banking.dkb.de:443 "GET /api/broker/brokerage-accounts HTTP/1.1" 200 None
DKBRobo._get_loans()

https://banking.dkb.de:443 "GET /api/loans/loans HTTP/1.1" 200 None
DKBRobo._build_account_list()

DKBRobo._build_product_settings_dic()

DKBRobo._sort_product_group()

DKBRobo._get_account_details(65fad2ba-6e47-4343-ab57-43ab01446dd0)

DKBRobo._add_accountinformation()

DKBRobo._add_accountdetails()

DKBRobo._add_accountbalance()

DKBRobo._add_accountname()

DKBRobo._sort_product_group()

DKBRobo._get_account_details(01fdb729-4d04-4763-ab1b-c937a3132e70)

DKBRobo._add_accountinformation()

DKBRobo._add_accountdetails()

DKBRobo._add_accountbalance()

DKBRobo._add_accountname()

DKBRobo._get_brokerage_details(b45fb735-947e-3f6f-a213-c0452180a4f3)

DKBRobo._add_brokerageinformation()

DKBRobo._add_brokerage_performance()

DKBRobo._add_brokerageholder()

DKBRobo._do_sso_redirect()

https://banking.dkb.de:443 "POST /api/sso-redirect HTTP/1.1" 200 None
DKBRobo._new_instance()

_new_instance(): adding clientcookies.
DKBRobo._logout()

Starting new HTTPS connection (1): www.ib.dkb.de:443
https://www.ib.dkb.de:443 "GET /DkbTransactionBanking/banner.xhtml?$event=logout HTTP/1.1" 302 0
https://www.ib.dkb.de:443 "GET /logout.html HTTP/1.1" 200 None
Traceback (most recent call last):
  File "/home/fr810/Developer/dkb-robo/dkb_robo/cli.py", line 220, in <module>
    main()
  File "/usr/lib/python3/dist-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/click/core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/fr810/Developer/dkb-robo/dkb_robo/cli.py", line 76, in accounts
    del value["details"]
        ~~~~~^^^^^^^^^^^
KeyError: 'details'

Reserved Transactions always empty in new Mode

hello there

when i try to obtain open transactions I always end up with an empty dict. Is the keyword reserved correct? I'm using the new method.

tlist = dkb.get_transactions("link", "account", "01.11.2023", "14.11.2025", "reserved" )
 pprint(tlist)

PSD2 API Solution - CREALOGiX

Hi all, Hallo zusammen,

I was searching for alternatives which are similar with Comdirect API Key Functionality where you can sign in with a bearer token (oauth2) and collect your own transaction informations like all activities and other valuable informations.

What I've found was a similar solution offered by a partner of DKB named "CREALOGix" and I'll try to build for myself a python-backend to collect my personal (non-commercial) financial informations to track them more automatically.

Why I'm writing this, maybe some of you or maybe @grindsa you have some hints which you can share or maybe contribute to build a personal Application. Of course it is not for commercial use in big and wide scale for consumers, because you have to organise your own keys and manage them into the python-script / config.ini / environment Variables.

I've attached the official documentation and sorry for abusing your issue tracking list for insisting an extending alternative to your great work. By the way I'm working with your library for a while and it is great. I also follow you 👍🏼

Best regards and have a nice Sunday,
Abda
PSD2 API Solution DKB - Documentation for TPPs v1.0.pdf

New|Alternative DKB Frontend starting May 2023

Hey Guys,

DKB is launching an (alternative) login page: https://bank.dkb.de/dein-neues-banking/?wt_mc=pk.ba_ga.fsm.lang.g.230417.

Schneller ins neue Banking – die Login-Seite ändert sich
Ab Anfang Mai gibt es frischen Wind auf deiner Anmeldeseite. Du kannst dich wie gewohnt im bisherigen Banking anmelden oder mit deinen Anmeldedaten das neue Banking ausprobieren.

The transaction list seems to be limited to 1 Year:

Du hast das Ende deiner Umsatzliste erreicht. Wir können Umsätze bis zu 360 Tage anzeigen.

They also seem to change the csv format a bit:

"Konto";"<NAME> <IBAN>"
""
"Kontostand vom <DATE>:";"<AMOUNT> EUR"
""
"Buchungsdatum";"Wertstellung";"Status";"Zahlungspflichtige*r";"Zahlungsempfänger*in";"Verwendungszweck";"Umsatztyp";"Betrag";"Gläubiger-ID";"Mandatsreferenz";"Kundenreferenz"

Double Name - only one downloaded

i have in archive in messages 5 file with name Informationsbogen zur Einlagensicherung

i used this command to download all files:

> document_dic = dkb.scan_postbox(path, True, True)

as result i get only one document downloaded.

with same name it should have a incrementing counter

Mandatsreferenz missing

Ticket #11 mentions a 'mandatsreferenz' field in the data but it is missing when I fetch using v0.24. Maybe something changed with the naming of the CSV? When I manually fetch a CSV from the website, it contains a "Mandatsreferenz" column.

Never uses TAN even if tan_insert is True

Thank you for this great project. This is exactly what I need!!

Unfortunately, no matter if tan_insert is True or False, dkb-robo will always ask for confirmation via the banking app. For example:

python3 dkb_robo/cli.py --debug -u xxxxx -p xxx --use-tan accounts 
DKBRobo._login()

DKBRobo._new_session()

Starting new HTTPS connection (1): banking.dkb.de:443
https://banking.dkb.de:443 "GET /login HTTP/1.1" 200 None
DKBRobo._get_token()

https://banking.dkb.de:443 "POST /api/token HTTP/1.1" 200 None
DKBRobo._get_mfa_methods()

https://banking.dkb.de:443 "GET /api/mfa/mfa/methods?filter%5BmethodType%5D=seal_one HTTP/1.1" 200 None
_select_mfa_device()

Pick an authentication device from the below list:
[0] - DKB-App on XXXXXX
[1] - DKB-App on XXXXXX
[2] - DKB-App on XXXXXX
:0

The same occurs if I edit line 27 of the dkb_example.py as follows:

    with DKBRobo(DKB_USER, DKB_PASSWORD, True, False) as dkb:

The same problem occurs.

Changing information

Hi all,

I'm getting transformation with your great library and having issues getting unique information: sometimes a few days later, the text of the transaction, the type and also the partner changes some information. e.g. the partner is shown just with the name the first day, a few days later i get the partner with address on the next day. Also the transaction type changes.

Do you guys also observe this behaviour? Do you have mitigations measures identified to uniquely identify a transaction?

Best
Ralph

Checking for valid minimal date when getting transactions

DKB only allows to get transactions up to three years in the past. If you want to get all your transactions and use e.g. 01.01.1970 as your date_from, setting the from and to fields does not work. The request will therefore return all transactions in the default timeframe (i.e. the last 30 days).

This unwanted effect could be mitigated by adding a feature to validate_dates that not only checks if the dates are not in the future, but also not more than three years in the past:

minimal_date_uts = int(time.mktime(datetime.date.today() - datetime.timedelta(days=3*365).timetuple()))
if date_from_uts < minimal_date_uts:
        date_from = datetime.utcfromtimestamp(minimal_date_uts).strftime('%d.%m.%Y')
if date_to_uts < minimal_date_uts:
        date_to = datetime.utcfromtimestamp(minimal_date_uts).strftime('%d.%m.%Y')

AttributeError: 'NoneType' object has no attribute 'find'

i executed the example doc_downloads with archive and download all:

> document_dic = dkb.scan_postbox(path, True, True)

i got this error:

Writing documents to /Users/muescha/Documents/DKB/
Traceback (most recent call last):
  File "/Users/muescha/Work/github.com/grindsa/dkb-robo/dkb_docdownload.py", line 35, in <module>
    POSTBOX_DIC = dkb.scan_postbox(PATH,True,True)
  File "/Users/muescha/Work/github.com/grindsa/dkb-robo/dkb_robo/dkb_robo.py", line 964, in scan_postbox
    pb_dic[link_name]['documents'] = self._get_document_links(pb_dic[link_name]['details'], path, link_name, select_all)
  File "/Users/muescha/Work/github.com/grindsa/dkb-robo/dkb_robo/dkb_robo.py", line 225, in _get_document_links
    table = soup.find('table', attrs={'class': 'widget widget abaxx-table expandableTable expandableTable-with-sort'})
AttributeError: 'NoneType' object has no attribute 'find'

Filename issues when downloading documents with scan_postbox

Hey, thanks for this very useful library. I used it for the very first time today and one of my primary use cases is to grab new documents from the postbox.

I encountered the following issues with the downloaded documents:

Encoding problems

Steuerbescheinigungen

 Length Name
 ------ ----
1436671 Ertr%c3%a4gnisaufstellung_2021_redacted.pdf

Vertragsinformationen

 Length Name
 ------ ----
 985260 %c3%84nderungsangebot_zum_01.01.2023_-_Vermieterpaket.pdf
4720661 %c3%84nderungsangebot_zum_01.01.2023.pdf
  12718 Mitteilung_%c3%bcber_steigende_Sollzinss%c3%a4tze_ab_01.10.2022.pdf

Wertpapierdokumente

Length Name
------ ----
 56873 allgemeine_Anschreiben_Kapitalma%c3%9fnahmen_vom_05.09.2022_zu_Depot_redacted_-_51567359221656A2QK20.pdf
 56804 allgemeine_Anschreiben_Kapitalma%c3%9fnahmen_vom_28.09.2022_zu_Depot_redacted_-_51572762221324A2QK20.pdf
 48144 Kauf_-_WKN_A2PKXG_-_Auftragsbest%c3%a4tigung_vom_17.06.2022_zu_Depot_redacted_-_Ordernr._6487281200.pdf
 48143 Kauf_-_WKN_A2PKXG_-_Auftragsbest%c3%a4tigung_vom_17.06.2022_zu_Depot_redacted_-_Ordernr._6487377900.pdf
 47735 Kauf_-_WKN_A2PKXG_-_Streichungsbest%c3%a4tigung_vom_31.08.2022_zu_Depot_redacted_-_Ordernr._6487281200.pdf
 47737 Kauf_-_WKN_A2PKXG_-_Streichungsbest%c3%a4tigung_vom_31.08.2022_zu_Depot_redacted_-_Ordernr._6487377900.pdf
 48301 Kauf_-_WKN_A2QK20_-_Auftragsbest%c3%a4tigung_vom_27.06.2022_zu_Depot_redacted_-_Ordernr._6585736100.pdf
 48443 Kauf_-_WKN_A2QK20_-_Auftragsbest%c3%a4tigung_vom_28.06.2022_zu_Depot_redacted_-_Ordernr._6585736100.pdf
 48754 Kauf_-_WKN_A2QK20_-_Ausf%c3%bchrungsanzeige_vom_29.06.2022_zu_Depot_redacted_-_Ordernr._6585736101.pdf
 58119 Kosteninformation_f%c3%bcr_das_Jahr_2022_zu_Depot_redacted.pdf

Zero length files / missing file extension

Length Name
------ ----
     0 Kosteninformation_zu_Wertpapier_ROMEO_POWER_INC._REG._SHARES_CL.A_DL_-_0001_vom_27.06.2022__21
     0 Kosteninformation_zu_Wertpapier_VANGUARD_FTSE_ALL-WORLD_U.ETF_REG._SHS_USD_ACC._ON_vom_17.06.2022__01

Edit: the problematic files have the following names in the postbox and this is the corresponding download link:

Name: Kosteninformation zu Wertpapier ROMEO POWER INC. REG. SHARES CL.A DL -,0001 vom 27.06.2022, 21:23 zu Depot redacted
Link: https://www.dkb.de/DkbTransactionBanking/content/mailbox/MessageList.xhtml?$event=getMailboxAttachment&filename=Kosteninformation+zu+Wertpapier+ROMEO+POWER+INC.+REG.+SHARES+CL.A++DL+-%2C0001+vom+27.06.2022%2C+21%3A23+zu+Depot+redacted&row=15
Name: Kosteninformation zu Wertpapier VANGUARD FTSE ALL-WORLD U.ETF REG. SHS USD ACC. ON vom 17.06.2022, 01:06 zu Depot redacted
Link: https://www.dkb.de/DkbTransactionBanking/content/mailbox/MessageList.xhtml?$event=getMailboxAttachment&filename=Kosteninformation+zu+Wertpapier+VANGUARD+FTSE+ALL-WORLD+U.ETF+REG.+SHS+USD+ACC.+ON+vom+17.06.2022%2C+01%3A06+zu+Depot+redacted&row=19

Let me know how I can help you get these two issues resolved :-)

date_from/date_to not handled correctly in get_creditcard_transactions

In function get_creditcard_transactions:
radio button filterType is set by the code correctly to:

self.dkb_br["filterType"] = 'DATE_RANGE'
self.dkb_br["postingDate"] = str(date_from)
self.dkb_br["toPostingDate"] = str(date_to)

but return values are always, like it has been set to:

self.dkb_br["filterType"] = 'PERIOD'
self.dkb_br["slSearchPeriod"] = 0

As result, the transactions returned by DKB are always since last balance accounting. date_from is not considered.

A code review shows no errors, however the results are wrong. Can anybody confirm this behavior?

LinkNotFoundError when trying to log in

I tried to get some / any data with the following script

#!/usr/bin/env python

import sys
from dkb_robo import DKBRobo
from pprint import pprint

def main():
    argv = sys.argv
    dkb_user = argv[1]
    dkb_password = input('Password: ')
    tan_insert = True 
    debug = True
    with DKBRobo(dkb_user, dkb_password, tan_insert, debug) as dkb:
        pprint(dkb.account_dic)

if __name__ == '__main__':
    main()

and i get

2020-07-20 22:09:27.874086: DKBRobo.login()

2020-07-20 22:09:27.874139: DKBRobo.new_instance()

2020-07-20 22:09:29.219896: DKBRobo.ctan_check()

Traceback (most recent call last):
  File "[...]/bankstats_cli", line 11, in <module>
    load_entry_point('Bankstats', 'console_scripts', 'bankstats_cli')()
  File "[...]cli.py", line 14, in main
    with DKBRobo(dkb_user, dkb_password, tan_insert, debug) as dkb:
  File "[...]/venv/lib/python3.8/site-packages/dkb_robo/dkb_robo.py", line 65, in __enter__
    self.login()
  File "[...]/venv/lib/python3.8/site-packages/dkb_robo/dkb_robo.py", line 493, in login
    login_confirmed = self.ctan_check(soup)
  File "[...]/venv/lib/python3.8/site-packages/dkb_robo/dkb_robo.py", line 508, in ctan_check
    self.dkb_br.select_form('form[name="confirmForm"]')
  File "[...]/venv/lib/python3.8/site-packages/mechanicalsoup/stateful_browser.py", line 207, in select_form
    raise LinkNotFoundError()
mechanicalsoup.utils.LinkNotFoundError

Some time (~ 10s) later i get a push notification via TAN2GO.

Am i missing something?

Error message

Hey i'm not too familiar with coding but i like this one and find it very useful. At one point, everything worked quiet well but since couple of weeks i get the error "Login failed: LinkNotFoundError".

I#m using python 3.9 on anaconda.

Thanks a lot.

Argument to pre-select which MFA device to use?

Hi there,

thanks for the work so far! I was super exited to find your repo.

One thought though, i have two smartphones registered as second factor, so every time i try to pull my transactions for a finance statistics script i am writing i get this prompt:

with DKBRobo(dkb_user="XXXXXXXX, dkb_password='XXXXXXXXXXX', tan_insert=False, legacy_login=False, debug=False) as dkb:
    acc = dkb.account_dic

Output:

Pick an authentication device from the below list:
[0] - DKB-App on iPhone
[1] - DKB-App on Fairphone FP4

could you maybe implement an argument to pre-select that device so one can avoid that user interaction?

Or is there maybe one i overlooked?

Cheers!

Why get transactions only for the last year?

Hi,

in dkb_robo.py, inside the get_transactions function you call validate_dates and pass the value 3 in case of legacy_login, and value 1 in case of new login to the min_year parameter. Can you explain why?

if self.legacy_login:
    (date_from, date_to) = validate_dates(self.logger, date_from, date_to, 3, self.legacy_login)
    transaction_list = self._legacy_get_transactions(transaction_url, atype, date_from, date_to, transaction_type)
else:
    (date_from, date_to) = validate_dates(self.logger, date_from, date_to, 1, self.legacy_login)
    transaction_list = self._get_transactions(transaction_url, atype, date_from, date_to, transaction_type)

I need to retrieve more than just one year, and if I change that parameter to a higher value, more that just one year is retrieved, meaning the API is supporting that. So, why do you limit that in the first place?

Regards

_build_account_dic returns empty dictionary

Hi,

very recently the robo stopped working. Login works, but account_dic is empty. I stepped into the problem and found out, that productGroups are empty in the data, that is sent by DKB:

{'product_display': {'data': [{'type': 'productDisplaySettings', 'id': '####################', 'attributes': {'portfolio': 'dkb', 'productSettings': {}, 'productGroups': {}, 'clientTypeSpecificSettings': {}}, 'links': {'self': 'https://api.developer.dkb.de/config/users/me/product-display-settings/####################'}}], 'included': []}

But _build_account_dic needs this data to build the account dic.
The rest of the portfolio_dic looks totally fine.
Without the productGroups, no account dic, no transaction_urls and no chance to get_transactions.

Tested versions 0.23.2 and 0.23.1, legacy_login=False

Anyone else has this issue? Is it really necessary to go via productGroups? It looks, like the account_dic could also be build without it.

Best regards

Mile&More Credit card breaks dkb-robo

Traceback (most recent call last):
File "/usr/lib64/python3.6/runpy.py", line 193, in _run_module_as_main
"main", mod_spec)
File "/usr/lib64/python3.6/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/home/wonko/git/wonko/dkb2influx/src/dkb2influx.py", line 15, in
transactions = dkb.get_transactions(account['transactions'], account['type'], date.today(), date(2017, 1, 1))
File "/home/wonko/git/github/dkb-robo/dkb_robo/dkb_robo.py", line 373, in get_transactions
transaction_list = self.get_creditcard_transactions(transaction_url, date_from, date_to)
File "/home/wonko/git/github/dkb-robo/dkb_robo/dkb_robo.py", line 115, in get_creditcard_transactions
self.dkb_br.select_form('#form1579108072_1')
File "/usr/lib64/python3.6/site-packages/mechanicalsoup/stateful_browser.py", line 207, in select_form
raise LinkNotFoundError()
mechanicalsoup.utils.LinkNotFoundError

LinkNotFoundError: br.select_form(#form1615473160_1) not leading to csv-export

Hi @grindsa,

apparently the function 'get_account_transactions' returns the error "LinkNotFoundError".

By inspecting the DKB-Page I found out that the form does exist and somehow I don't know exactly how to solve it by my own. Here are some insights of the error:

" LinkNotFoundError Traceback (most recent call last)
Cell In[5], line 8
5 date_from = '01.01.2022'
6 date_till = date.today().strftime('%d.%m.%Y')
----> 8 tlist = dkb.get_account_transactions(my_link, date_from, date_till, 'booked')
9 print(len(tlist))

File ~/Desktop/Private/03_CodingProjects/02_Python/FinanceTracker/.finances/lib/python3.11/site-packages/dkb_robo/dkb_robo.py:780, in DKBRobo.get_account_transactions(self, transaction_url, date_from, date_to, transaction_type)
778 self.dkb_br.open(transaction_url)
779 # don´t forget to correct it back to #form1615473160_1
--> 780 self.dkb_br.select_form('#form1615473160_1')
781 if transaction_type == 'reserved':
782 self.dkb_br["slTransactionStatus"] = 1

File ~/Desktop/Private/03_CodingProjects/02_Python/FinanceTracker/.finances/lib/python3.11/site-packages/mechanicalsoup/stateful_browser.py:241, in StatefulBrowser.select_form(self, selector, nr)
239 print('select_form failed for', selector)
240 self.launch_browser()
--> 241 raise LinkNotFoundError()
243 form = found_forms[-1]
245 if form and form.has_attr('id'):

LinkNotFoundError:

In your function you have it written (File 'Dkb_robo.py' -> Line: 779). Due the inspecting I've found the form ID also, but without the 'hash'- Symbol as you can see in the attached image.
DKB_Form_CSV-Download

I hope the issue is quickly solvable and doesn't takes much resources from your side.

Thanks in Advance and have a nice day!

Best regards,
Abda

Idea: Script to bulk download all documents

It would be great to have add the ability to actually download the documents per category in the DKB post box; and then having this as a standalone example.

Let me know what you think, I might then try to contribute something like that.

Update doc/dkb_example.py with new parameters

Hi,

I updated to the latest version, but it doesn't work as I expect.

However - as I am a copy&paste programmer :D - I checked the example to check, if I am doing somehting wrong, but I assume the current parameters are not part of the dkb_example.py

I am wondering, if the current example is working with the latest version...?

Regards
Christian

Depot transactions/status

I noticed that there is no method to handle the status of depots.
As I needed this, I added it for myself as part of the get_transaction methods, even if it is not really a list of transactions.

Is a pull request for this welcome?

Amount for an account for a given date

Hi,

is there a way to get the amount of an account for a given date ?
In the old interface you can filter your transactions for given time period and see the amount for this.
When you export these results as csv you also see your amount.

Would be great to get this feature.

Thanks for your work and kind regards
Andy

dkb-robo fails when the new "DKB" app is used to confirm login

Response for poll on
poll_url = self.base_url + '/DkbTransactionBanking/content/LoginWithBoundDevice/LoginWithBoundDeviceProcess/confirmLogin.xhtml'
returns 500 and for this the .json() method fails.

Here the trace:
DKBRobo.login()

DKBRobo.new_instance()

Starting new HTTPS connection (1): www.dkb.de
https://www.dkb.de:443 "GET /banking HTTP/1.1" 200 None
https://www.dkb.de:443 "POST /banking HTTP/1.1" 200 None
DKBRobo.login_confirm()

check your banking app and confirm login...
https://www.dkb.de:443 "GET /DkbTransactionBanking/content/LoginWithBoundDevice/LoginWithBoundDeviceProcess/confirmLogin.xhtml?$event=pollingVerification&_=0 HTTP/1.1" 500 21563
Traceback (most recent call last):
File "./dkb.py", line 14, in
with DKBRobo('xxxxxxxx', 'xxxxxx', False, True) as dkb:
File "/home/daniel/.local/lib/python3.6/site-packages/dkb_robo/dkb_robo.py", line 89, in enter
self.login()
File "/home/daniel/.local/lib/python3.6/site-packages/dkb_robo/dkb_robo.py", line 521, in login
login_confirmed = self.login_confirm()
File "/home/daniel/.local/lib/python3.6/site-packages/dkb_robo/dkb_robo.py", line 611, in login_confirm
result = response.json()
File "/home/daniel/.local/lib/python3.6/site-packages/requests/models.py", line 910, in json
return complexjson.loads(self.text, **kwargs)
File "/usr/lib/python3.6/json/init.py", line 354, in loads
return _default_decoder.decode(s)
File "/usr/lib/python3.6/json/decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python3.6/json/decoder.py", line 357, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.