First step on ING with Browser2

Login and listing of accounts work
This commit is contained in:
Florent 2014-03-27 23:48:16 +01:00
commit 15ca64f3d9
4 changed files with 105 additions and 111 deletions

View file

@ -26,7 +26,7 @@ from weboob.capabilities.base import UserError
from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.backend import BaseBackend, BackendConfig
from weboob.tools.value import ValueBackendPassword from weboob.tools.value import ValueBackendPassword
from .browser import Ing from .browser import IngBrowser
__all__ = ['INGBackend'] __all__ = ['INGBackend']
@ -49,7 +49,7 @@ class INGBackend(BaseBackend, ICapBank, ICapBill):
regexp='^(\d{8}|)$', regexp='^(\d{8}|)$',
masked=False) masked=False)
) )
BROWSER = Ing BROWSER = IngBrowser
def create_default_browser(self): def create_default_browser(self):
return self.create_browser(self.config['login'].get(), return self.create_browser(self.config['login'].get(),

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright(C) 2009-2011 Romain Bignon, Florent Fourcot # Copyright(C) 2009-2014 Florent Fourcot
# #
# This file is part of weboob. # This file is part of weboob.
# #
@ -19,74 +19,67 @@
import urllib import urllib
import hashlib import hashlib
from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword from weboob.tools.browser2 import LoginBrowser, URL, need_login
from weboob.tools.browser import BrowserIncorrectPassword
from weboob.capabilities.bank import Account, TransferError from weboob.capabilities.bank import Account, TransferError
from .pages import AccountsList, LoginPage, \ from .pages import AccountsList, LoginPage, \
TransferPage, TransferConfirmPage, \ TransferPage, TransferConfirmPage, \
BillsPage, StopPage, TitrePage, \ BillsPage, StopPage, TitrePage, \
TitreHistory TitreHistory
__all__ = ['Ing'] __all__ = ['IngBrowser']
class Ing(BaseBrowser): class IngBrowser(LoginBrowser):
DOMAIN = 'secure.ingdirect.fr' BASEURL = 'https://secure.ingdirect.fr'
PROTOCOL = 'https'
DEBUG_HTTP = False # '.*onHoldTransferManagement.jsf': TransferPage,
#DEBUG_HTTP = True # '.*displayCoordonneesCommand.*': StopPage,
ENCODING = None # '.*compteTempsReelCK.php.*': (TitrePage, 'raw'),
PAGES = {'.*pages/index.jsf.*': AccountsList, # '.*compte.php\?ong=3': TitreHistory,
'.*displayLogin.jsf.*': LoginPage,
'.*transferManagement.jsf': TransferPage, # Login and error
'.*onHoldTransferManagement.jsf': TransferPage, loginpage = URL('/public/displayLogin.jsf.*', LoginPage)
'.*DisplayDoTransferCommand.*': TransferPage, errorpage = URL('.*displayCoordonneesCommand.*', StopPage)
'.*transferCreateValidation.jsf': TransferConfirmPage,
'.*eStatement.jsf': BillsPage, # CapBank
'.*displayCoordonneesCommand.*': StopPage, accountspage = URL('/protected/pages/index.jsf', AccountsList)
'.*portefeuille-TR.*': (TitrePage, 'raw'), transferpage = URL('/protected/pages/cc/transfer/transferManagement.jsf', TransferPage)
'.*compteTempsReelCK.php.*': (TitrePage, 'raw'), dotransferpage = URL('/general?command=DisplayDoTransferCommand', TransferPage)
'.*compte.php\?ong=3': TitreHistory, valtransferpage = URL('/protected/pages/cc/transfer/create/transferCreateValidation.jsf', TransferConfirmPage)
} #transferonhold = URL('
CERTHASH = "257100e5f69b3c24b27eaaa82951ca5539e9ca264dee433b7c8d4779e778a0b4" titrepage = URL('https://bourse.ingdirect.fr/priv/portefeuille-TR.php', TitrePage)
titrehistory = URL('https://bourse.ingdirect.fr/priv/compte.php?ong=3', TitreHistory)
# CapBill
billpage = URL('/protected/pages/common/estatement/eStatement.jsf', BillsPage)
loginpage = '/public/displayLogin.jsf'
accountspage = '/protected/pages/index.jsf'
transferpage = '/protected/pages/cc/transfer/transferManagement.jsf'
dotransferpage = '/general?command=DisplayDoTransferCommand'
valtransferpage = '/protected/pages/cc/transfer/create/transferCreateValidation.jsf'
billpage = '/protected/pages/common/estatement/eStatement.jsf'
titrepage = 'https://bourse.ingdirect.fr/priv/portefeuille-TR.php'
where = None where = None
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.birthday = kwargs.pop('birthday', None) self.birthday = kwargs.pop('birthday', None)
BaseBrowser.__init__(self, *args, **kwargs) LoginBrowser.__init__(self, *args, **kwargs)
def home(self): def do_login(self):
self.location(self.loginpage)
def is_logged(self):
return not self.is_on_page(LoginPage)
def login(self):
assert isinstance(self.username, basestring) assert isinstance(self.username, basestring)
assert isinstance(self.password, basestring) assert isinstance(self.password, basestring)
assert isinstance(self.birthday, basestring) assert isinstance(self.birthday, basestring)
assert self.password.isdigit() assert self.password.isdigit()
assert self.birthday.isdigit() assert self.birthday.isdigit()
if not self.is_on_page(LoginPage): self.loginpage.stay_or_go()
self.location(self.loginpage)
self.page.prelogin(self.username, self.birthday) self.page.prelogin(self.username, self.birthday)
self.page.login(self.password) self.page.login(self.password)
if self.page.error(): if self.page.error():
raise BrowserIncorrectPassword() raise BrowserIncorrectPassword()
@need_login
def get_accounts_list(self): def get_accounts_list(self):
if not self.is_on_page(AccountsList) or self.where != "start": self.accountspage.go()
self.location(self.accountspage)
self.where = "start" self.where = "start"
return self.page.get_list() return self.page.get_list()

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright(C) 2009-2011 Romain Bignon, Florent Fourcot # Copyright(C) 2009-2014 Florent Fourcot, Romain Bignon
# #
# This file is part of weboob. # This file is part of weboob.
# #
@ -25,7 +25,8 @@ import hashlib
from weboob.capabilities.bank import Account from weboob.capabilities.bank import Account
from weboob.capabilities.base import NotAvailable from weboob.capabilities.base import NotAvailable
from weboob.tools.browser import BasePage from weboob.tools.browser2.page import HTMLPage, method, ListElement, ItemElement
from weboob.tools.browser2.filters import Attr, CleanText, CleanDecimal, Filter, Field, MultiFilter
from weboob.tools.capabilities.bank.transactions import FrenchTransaction from weboob.tools.capabilities.bank.transactions import FrenchTransaction
@ -42,9 +43,31 @@ class Transaction(FrenchTransaction):
] ]
class AccountsList(BasePage): class AddPref(MultiFilter):
def on_loaded(self): prefixes = {u'Courant': u'CC-', u'Livret A': 'LA-', u'Orange': 'LEO-',
pass u'Durable': u'LDD-', u"Titres": 'TITRE-', u'PEA': u'PEA-'}
def filter(self, values):
el, label = values
for key, pref in self.prefixes.items():
if key in label:
return pref + el
return el
class AddType(Filter):
types = {u'Courant': Account.TYPE_CHECKING, u'Livret A': Account.TYPE_SAVINGS,
u'Orange': Account.TYPE_SAVINGS, u'Durable': Account.TYPE_SAVINGS,
u'Titres': Account.TYPE_MARKET, u'PEA': Account.TYPE_MARKET}
def filter(self, label):
for key, acc_type in self.types.items():
if key in label:
return acc_type
return Account.TYPE_UNKNOWN
class AccountsList(HTMLPage):
monthvalue = {u'janv.': '01', u'févr.': '02', u'mars': '03', u'avr.': '04', monthvalue = {u'janv.': '01', u'févr.': '02', u'mars': '03', u'avr.': '04',
u'mai': '05', u'juin': '06', u'juil.': '07', u'août': '08', u'mai': '05', u'juin': '06', u'juil.': '07', u'août': '08',
@ -55,38 +78,22 @@ class AccountsList(BasePage):
u'cb_ach': u'Carte achat', u'chq': u'Chèque', u'cb_ach': u'Carte achat', u'chq': u'Chèque',
u'frais': u'Frais bancaire', u'sepaplvt': u'Prélèvement'} u'frais': u'Frais bancaire', u'sepaplvt': u'Prélèvement'}
def get_list(self): @method
# TODO: no idea abount how proxy account are displayed class get_list(ListElement):
for a in self.document.xpath('//a[@class="mainclic"]'): item_xpath = '//a[@class="mainclic"]'
account = Account()
account.currency = u'EUR' class item(ItemElement):
account.id = unicode(a.find('span[@class="account-number"]').text) klass = Account
account._id = account.id
account.label = unicode(a.find('span[@class="title"]').text) obj_currency = u'EUR'
balance = a.find('span[@class="solde"]/label').text obj__id = CleanText('span[@class="account-number"]')
account.balance = Decimal(FrenchTransaction.clean_amount(balance)) obj_label = CleanText('span[@class="title"]')
account.coming = NotAvailable obj_id = AddPref(Field('_id'), Field('label'))
if "Courant" in account.label: obj_type = AddType(Field('label'))
account.id = "CC-" + account.id obj_balance = CleanDecimal('span[@class="solde"]/label')
account.type = Account.TYPE_CHECKING obj_coming = NotAvailable
elif "Livret A" in account.label: obj__jid = Attr('//input[@name="javax.faces.ViewState"]', 'value')
account.id = "LA-" + account.id
account.type = Account.TYPE_SAVINGS
elif "Orange" in account.label:
account.id = "LEO-" + account.id
account.type = Account.TYPE_SAVINGS
elif "Durable" in account.label:
account.id = "LDD-" + account.id
account.type = Account.TYPE_SAVINGS
elif "Titres" in account.label:
account.id = "TITRE-" + account.id
account.type = Account.TYPE_MARKET
elif "PEA" in account.label:
account.id = "PEA-" + account.id
account.type = Account.TYPE_MARKET
jid = self.document.find('//input[@name="javax.faces.ViewState"]')
account._jid = jid.attrib['value']
yield account
def get_transactions(self, index): def get_transactions(self, index):
i = 0 i = 0

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright(C) 2009-2011 Romain Bignon, Florent Fourcot # Copyright(C) 2009-2014 Florent Fourcot, Romain Bignon
# #
# This file is part of weboob. # This file is part of weboob.
# #
@ -17,13 +17,13 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from StringIO import StringIO
from weboob.tools.mech import ClientForm
from logging import error from logging import error
from weboob.tools.browser import BasePage, BrowserIncorrectPassword from weboob.tools.browser import BasePage, BrowserIncorrectPassword
from weboob.tools.captcha.virtkeyboard import VirtKeyboard, VirtKeyboardError from weboob.tools.captcha.virtkeyboard import VirtKeyboard, VirtKeyboardError
from weboob.tools.browser2.page import HTMLPage
__all__ = ['LoginPage', 'INGVirtKeyboard', 'StopPage'] __all__ = ['LoginPage', 'INGVirtKeyboard', 'StopPage']
@ -43,9 +43,9 @@ class INGVirtKeyboard(VirtKeyboard):
color = 64 color = 64
def __init__(self, basepage): def __init__(self, basepage):
divkeyboard = basepage.document.find("//div[@id='clavierdisplayLogin']") divkeyboard = basepage.doc.find("//div[@id='clavierdisplayLogin']")
if divkeyboard is None: if divkeyboard is None:
divkeyboard = basepage.document.find("//div[@id='claviertransfer']") divkeyboard = basepage.doc.find("//div[@id='claviertransfer']")
try: try:
img = divkeyboard.xpath("img")[1] img = divkeyboard.xpath("img")[1]
except: except:
@ -63,7 +63,7 @@ class INGVirtKeyboard(VirtKeyboard):
coords["42"] = (125, 45, 153, 73) coords["42"] = (125, 45, 153, 73)
coords["52"] = (165, 45, 193, 73) coords["52"] = (165, 45, 193, 73)
VirtKeyboard.__init__(self, basepage.browser.openurl(url), coords, self.color) VirtKeyboard.__init__(self, StringIO(basepage.browser.open(url).content), coords, self.color)
self.check_symbols(self.symbols, basepage.browser.responses_dirname) self.check_symbols(self.symbols, basepage.browser.responses_dirname)
@ -84,23 +84,19 @@ class INGVirtKeyboard(VirtKeyboard):
return code return code
class LoginPage(BasePage): class LoginPage(HTMLPage):
def on_loaded(self):
pass
def prelogin(self, login, birthday): def prelogin(self, login, birthday):
# First step : login and birthday # First step : login and birthday
self.browser.select_form('zone1Form') form = self.get_form(name='zone1Form')
self.browser.set_all_readonly(False) form['zone1Form:numClient'] = login
self.browser['zone1Form:numClient'] = str(login) form['zone1Form:dateDay'] = birthday[0:2]
self.browser['zone1Form:dateDay'] = str(birthday[0:2]) form['zone1Form:dateMonth'] = birthday[2:4]
self.browser['zone1Form:dateMonth'] = str(birthday[2:4]) form['zone1Form:dateYear'] = birthday[4:9]
self.browser['zone1Form:dateYear'] = str(birthday[4:9]) form['zone1Form:idRememberMyCifCheck'] = False
self.browser['zone1Form:idRememberMyCifCheck'] = False form.submit()
self.browser.submit(nologin=True)
def error(self): def error(self):
err = self.document.find('//span[@class="error"]') err = self.doc.find('//span[@class="error"]')
return err is not None return err is not None
def login(self, password): def login(self, password):
@ -111,22 +107,20 @@ class LoginPage(BasePage):
error("Error: %s" % err) error("Error: %s" % err)
return False return False
realpasswd = "" realpasswd = ""
span = self.document.find('//span[@id="digitpaddisplayLogin"]') span = self.doc.find('//span[@id="digitpaddisplayLogin"]')
i = 0 i = 0
for font in span.getiterator('font'): for font in span.getiterator('font'):
if font.attrib.get('class') == "vide": if font.attrib.get('class') == "vide":
realpasswd += password[i] realpasswd += password[i]
i += 1 i += 1
self.browser.logger.debug('We are looking for : ' + realpasswd) self.browser.logger.debug('We are looking for : ' + realpasswd)
self.browser.select_form('mrc')
self.browser.set_all_readonly(False)
self.browser.logger.debug("Coordonates: " + vk.get_string_code(realpasswd)) self.browser.logger.debug("Coordonates: " + vk.get_string_code(realpasswd))
self.browser.controls.append(ClientForm.TextControl('text', 'mrc:mrg', {'value': ''}))
self.browser.controls.append(ClientForm.TextControl('text', 'AJAXREQUEST', {'value': ''})) form = self.get_form(name='mrc')
self.browser['AJAXREQUEST'] = '_viewRoot' form['mrc:mrg'] = 'mrc:mrg'
self.browser['mrc:mrldisplayLogin'] = vk.get_string_code(realpasswd) form['AJAXREQUEST'] = '_viewRoot'
self.browser['mrc:mrg'] = 'mrc:mrg' form['mrc:mrldisplayLogin'] = vk.get_string_code(realpasswd)
self.browser.submit(nologin=True) form.submit()
class StopPage(BasePage): class StopPage(BasePage):