def iter_accounts(self): if 'accs' not in self.cache.keys(): no_accounts_message = None self.accounts.stay_or_go(slug=self.SLUG, lang=self.LANG) # weird wrongpass if not self.accounts.is_here(): raise BrowserIncorrectPassword() multi = self.page.get_multi() if len(multi): # Handle multi entreprise accounts accs = [] for id in multi: self.page.go_multi(id) self.accounts.go(slug=self.SLUG) if not no_accounts_message: no_accounts_message = self.page.get_no_accounts_message( ) for a in self.page.iter_accounts(): a._multi = id accs.append(a) else: no_accounts_message = self.page.get_no_accounts_message() accs = [a for a in self.page.iter_accounts()] if not len(accs) and no_accounts_message: # Accounts list is empty and we found the # message on at least one of the spaces: raise NoAccountsException(no_accounts_message) self.cache['accs'] = accs return self.cache['accs']
def check_no_accounts(self): no_account_message = CleanText( u'//span[@id="MM_LblMessagePopinError"]/p[contains(text(), "Aucun compte disponible")]' )(self.doc) if no_account_message: raise NoAccountsException(no_account_message)
def get_accounts_list(self): if self.accounts is None: accounts = [] self.par_accounts_checking.go() pages = [ self.par_accounts_checking, self.par_accounts_savings_and_invests, self.par_accounts_loan ] no_accounts = 0 for page in pages: page.go() if self.page.no_accounts: no_accounts += 1 continue for account in self.page.iter_accounts(): accounts.append(account) if self.page.has_mandate_management_space: self.location(self.page.mandate_management_space_link()) for mandate_account in self.page.iter_accounts(): accounts.append(mandate_account) self.accounts = accounts # if we are sure there is no accounts on the all visited pages, # it is legit. if no_accounts == len(pages): raise NoAccountsException() return self.accounts
def on_load(self): if self.doc['commun']['statut'] == 'NOK': reason = self.doc['commun']['raison'] if reason == 'SYD-COMPTES-UNAUTHORIZED-ACCESS': raise NoAccountsException( "Vous n'avez pas l'autorisation de consulter : {}".format( reason)) raise BrowserUnavailable(reason)
def open(self, *args, **kwargs): try: return super(HSBCHK, self).open(*args, **kwargs) except ClientError as e: if e.response.status_code == 401: self.auth_token = None self.logged = False self.session.cookies.clear() raise LoggedOut() if e.response.status_code == 409: raise NoAccountsException() raise
def on_load(self): self.browser.open( "https://voscomptesenligne.labanquepostale.fr/voscomptes/canalXHTML/securite/authentification/verifierMotDePasse-identif.ea" ) if self.doc.xpath( u'//span[contains(text(), "L\'identifiant utilisé est celui d\'une Entreprise ou d\'une Association")]' ): raise BrowserIncorrectPassword( u"L'identifiant utilisé est celui d'une Entreprise ou d'une Association" ) no_accounts = CleanText(u'//div[@class="textFCK"]')(self.doc) if no_accounts: raise NoAccountsException(no_accounts) MyHTMLPage.on_load(self)
def on_load(self): no_accounts_message = CleanText( '//span[contains(text(), "On this date, you still have no employee savings in this company.")] | \ //span[contains(text(), "On this date, you do not yet have any employee savings in this company.")] | \ //span[contains(text(), "On this date, you no longer have any employee savings in this company.")]' )(self.doc) if no_accounts_message: raise NoAccountsException(no_accounts_message) if CleanText( '//a//span[contains(text(), "J\'ACCEPTE LES CONDITIONS GENERALES D\'UTILISATION") or' ' contains(text(), "I ACCEPT THE GENERAL CONDITIONS OF USE")]' )(self.doc): raise ActionNeeded( "Veuillez valider les conditions générales d'utilisation")
def on_load(self): if self.doc['commun']['statut'].lower() == 'nok': reason = self.doc['commun']['raison'] if reason == 'SYD-COMPTES-UNAUTHORIZED-ACCESS': raise NoAccountsException( "Vous n'avez pas l'autorisation de consulter : {}".format( reason)) elif reason == 'niv_auth_insuff': raise BrowserIncorrectPassword( 'Vos identifiants sont incorrects') elif reason == 'chgt_mdp_oblig': raise BrowserPasswordExpired( 'Veuillez renouveler votre mot de passe') elif reason == 'oob_insc_oblig': raise AuthMethodNotImplemented( "L'authentification par Secure Access n'est pas prise en charge" ) raise BrowserUnavailable(reason)
def get_accounts_list(self): if self.accounts is None: accounts = [] self.par_accounts_checking.go() pages = [ self.par_accounts_checking, self.par_accounts_savings_and_invests, self.par_accounts_loan ] no_accounts = 0 for page in pages: page.go() assert page.is_here(), "AccountList type page not reached" if self.page.no_accounts: no_accounts += 1 continue for account in self.page.iter_accounts(): if account.type == Account.TYPE_LOAN: self.location(account.url) if 'CreditRenouvelable' not in account.url: for loan in self.page.iter_loans(): accounts.append(loan) else: for loan in self.page.iter_revolving_loans(): accounts.append(loan) else: accounts.append(account) if self.page.has_mandate_management_space: self.location(self.page.mandate_management_space_link()) for mandate_account in self.page.iter_accounts(): accounts.append(mandate_account) self.accounts = accounts # if we are sure there is no accounts on the all visited pages, # it is legit. if no_accounts == len(pages): raise NoAccountsException() return self.accounts
def get_numbers(self): if 'listCompteTitulaireCotitulaire' not in self.doc and 'exception' in self.doc: raise NoAccountsException() ret = {} ret.update({ d['index']: d['numeroContratSouscrit'] for d in self.doc['listCompteTitulaireCotitulaire'] }) ret.update({ d['index']: d['numeroContratSouscrit'] for p in self.doc['listCompteMandataire'].values() for d in p }) ret.update({ d['index']: d['numeroContratSouscrit'] for p in self.doc['listCompteLegalRep'].values() for d in p }) return ret
def on_load(self): if self.doc['commun']['statut'].lower() == 'nok': reason = self.doc['commun']['raison'] if reason == 'SYD-COMPTES-UNAUTHORIZED-ACCESS': raise NoAccountsException( "Vous n'avez pas l'autorisation de consulter : {}".format( reason)) elif reason == 'niv_auth_insuff': return elif reason in ('chgt_mdp_oblig', 'chgt_mdp_init'): raise BrowserPasswordExpired( 'Veuillez vous rendre sur le site de la banque pour renouveler votre mot de passe' ) elif reason == 'oob_insc_oblig': raise AuthMethodNotImplemented( "L'authentification par Secure Access n'est pas prise en charge" ) else: # the BrowserUnavailable was raised for every unknown error, and was masking the real error. # So users and developers didn't know what kind of error it was. assert False, 'Error %s is not handled yet.' % reason
def get_list(self): err = CleanText('//span[@class="error_msg"]', default='')(self.doc) if err == 'Vous ne disposez pas de compte consultable.': raise NoAccountsException() def check_valid_url(url): pattern = [ '/restitution/cns_detailAVPAT.html', '/restitution/cns_detailAlterna.html', ] for p in pattern: if url.startswith(p): return False return True for tr in self.doc.getiterator('tr'): if 'LGNTableRow' not in tr.attrib.get('class', '').split(): continue account = Account() for td in tr.getiterator('td'): if td.attrib.get('headers', '') == 'TypeCompte': a = td.find('a') if a is None: break account.label = CleanText('.')(a) account._link_id = a.get('href', '') for pattern, actype in self.TYPES.items(): if account.label.startswith(pattern): account.type = actype break else: if account._link_id.startswith('/asv/asvcns10.html'): account.type = Account.TYPE_LIFE_INSURANCE # Website crashes when going on theses URLs if not check_valid_url(account._link_id): account._link_id = None elif td.attrib.get('headers', '') == 'NumeroCompte': account.id = CleanText(u'.', replace=[(' ', '')])(td) elif td.attrib.get('headers', '') == 'Libelle': text = CleanText('.')(td) if text != '': account.label = text elif td.attrib.get('headers', '') == 'Solde': div = td.xpath('./div[@class="Solde"]') if len(div) > 0: balance = CleanText('.')(div[0]) if len(balance) > 0 and balance not in ('ANNULEE', 'OPPOSITION'): try: account.balance = Decimal( FrenchTransaction.clean_amount(balance)) except InvalidOperation: self.logger.error( 'Unable to parse balance %r' % balance) continue account.currency = account.get_currency(balance) else: account.balance = NotAvailable if not account.label or empty(account.balance): continue if account._link_id and 'CARTE_' in account._link_id: account.type = account.TYPE_CARD if account.type == Account.TYPE_UNKNOWN: self.logger.debug('Unknown account type: %s', account.label) yield account
def get_accounts_list(self): if self.session.cookies.get('indicateur'): # Malformed cookie to delete to reach other spaces del self.session.cookies['indicateur'] if self.accounts is None: accounts = [] to_check = [] self.par_accounts_checking.go() pages = [self.par_accounts_checking, self.par_accounts_savings_and_invests, self.par_accounts_loan] no_accounts = 0 for page in pages: page.go() assert page.is_here(), "AccountList type page not reached" if self.page.no_accounts: no_accounts += 1 continue for account in self.page.iter_accounts(): if account.type == Account.TYPE_LOAN: self.location(account.url) if 'initSSO' not in account.url: for loan in self.page.iter_loans(): loan.currency = account.currency accounts.append(loan) student_loan = self.page.get_student_loan() if student_loan: # Number of headers and item elements are the same assert len(student_loan._heads) == len(student_loan._items) student_loan.currency = account.currency accounts.append(student_loan) else: # The main revolving page is not accessible, we can reach it by this new way self.location(self.absurl('/voscomptes/canalXHTML/sso/lbpf/souscriptionCristalFormAutoPost.jsp')) self.page.go_revolving() revolving_loan = self.page.get_revolving_attributes(account) accounts.append(revolving_loan) page.go() elif account.type == Account.TYPE_PERP: # PERP balances must be fetched from the details page, # otherwise we just scrape the "Rente annuelle estimée": balance = self.open(account.url).page.get_balance() if balance is not None: account.balance = balance accounts.append(account) else: accounts.append(account) if account.type == Account.TYPE_CHECKING and account._has_cards: to_check.append(account) if self.page.has_mandate_management_space: self.location(self.page.mandate_management_space_link()) for mandate_account in self.page.iter_accounts(): accounts.append(mandate_account) for account in to_check: accounts.extend(self.iter_cards(account)) to_check = [] self.accounts = accounts # if we are sure there is no accounts on the all visited pages, # it is legit. if no_accounts == len(pages): raise NoAccountsException() return self.accounts
def get_accounts_list(self): if not self.accounts_list: if self.currentSubBank is None: self.getCurrentSubBank() self.two_cards_page = None self.accounts_list = [] self.revolving_accounts = [] self.unavailablecards = [] self.cards_histo_available = [] self.cards_list =[] self.cards_list2 =[] # For some cards the validity information is only availaible on these 2 links self.cards_hist_available.go(subbank=self.currentSubBank) if self.cards_hist_available.is_here(): self.unavailablecards.extend(self.page.get_unavailable_cards()) for acc in self.page.iter_accounts(): acc._referer = self.cards_hist_available self.accounts_list.append(acc) self.cards_list.append(acc) self.cards_histo_available.append(acc.id) if not self.cards_list: self.cards_hist_available2.go(subbank=self.currentSubBank) if self.cards_hist_available2.is_here(): self.unavailablecards.extend(self.page.get_unavailable_cards()) for acc in self.page.iter_accounts(): acc._referer = self.cards_hist_available2 self.accounts_list.append(acc) self.cards_list.append(acc) self.cards_histo_available.append(acc.id) for acc in self.revolving_loan_list.stay_or_go(subbank=self.currentSubBank).iter_accounts(): self.accounts_list.append(acc) self.revolving_accounts.append(acc.label.lower()) # Handle cards on tiers page self.cards_activity.go(subbank=self.currentSubBank) companies = self.page.companies_link() if self.cards_activity.is_here() else \ [self.page] if self.is_new_website else [] for company in companies: # We need to return to the main page to avoid navigation error self.cards_activity.go(subbank=self.currentSubBank) page = self.open(company).page if isinstance(company, basestring) else company for card in page.iter_cards(): card2 = find_object(self.cards_list, id=card.id[:16]) if card2: # In order to keep the id of the card from the old space, we exchange the following values card._link_id = card2._link_id card._parent_id = card2._parent_id card.coming = card2.coming card._referer = card2._referer card._secondpage = card2._secondpage self.accounts_list.remove(card2) self.accounts_list.append(card) self.cards_list2.append(card) self.cards_list.extend(self.cards_list2) # Populate accounts from old website if not self.is_new_website: self.logger.info('On old creditmutuel website') self.accounts.stay_or_go(subbank=self.currentSubBank) has_no_account = self.page.has_no_account() self.accounts_list.extend(self.page.iter_accounts()) self.iban.go(subbank=self.currentSubBank).fill_iban(self.accounts_list) self.por.go(subbank=self.currentSubBank) self.page.add_por_accounts(self.accounts_list) # Populate accounts from new website else: self.new_accounts.stay_or_go(subbank=self.currentSubBank) has_no_account = self.page.has_no_account() self.accounts_list.extend(self.page.iter_accounts()) self.iban.go(subbank=self.currentSubBank).fill_iban(self.accounts_list) self.por.go(subbank=self.currentSubBank) self.page.add_por_accounts(self.accounts_list) self.li.go(subbank=self.currentSubBank) self.accounts_list.extend(self.page.iter_li_accounts()) # This type of account is like a loan, for splitting payments in smaller amounts. # Its history is irrelevant because money is debited from a checking account and # the balance is not even correct, so ignore it. excluded_label = ['etalis', 'valorisation totale'] accounts_by_id = {} for acc in self.accounts_list: if acc.label.lower() not in excluded_label: accounts_by_id[acc.id] = acc # Set the parent to loans and cards accounts for acc in self.accounts_list: if acc.type == Account.TYPE_CARD and not empty(getattr(acc, '_parent_id', None)): acc.parent = accounts_by_id.get(acc._parent_id, NotAvailable) elif acc.type in (Account.TYPE_MORTGAGE, Account.TYPE_LOAN) and acc._parent_id: acc.parent = accounts_by_id.get(acc._parent_id, NotAvailable) self.accounts_list = list(accounts_by_id.values()) if has_no_account and not self.accounts_list: raise NoAccountsException(has_no_account) self.ownership_guesser() return self.accounts_list
def parse(self, el): msg = CleanText('//font[@color="#FF0000"]')(self) if msg and 'NO INFORMATION AVAILABLE.' in msg: raise NoAccountsException()
def parse(self, el): if not el.get('count', 42): raise NoAccountsException()
def on_load(self): if CleanText(u'//span[contains(text(), "vous ne disposez plus d\'épargne salariale")]')(self.doc): raise NoAccountsException()
def get_accounts_list(self): self.status.go() exc = None for x in range(3): if self.accounts_list is not None: break self.accounts_list = [] self.loans_list = [] # Check that there is at least one account for this user has_account = False self.pro_accounts.go() if self.pro_accounts.is_here(): self.accounts_list.extend(self.page.iter_accounts()) has_account = True else: # We dont want to let has_account=False if we landed on an unknown page # it has to be the no_accounts page assert self.no_account.is_here() try: self.accounts.go() except BrowserUnavailable as e: self.logger.warning('par accounts seem unavailable, retrying') exc = e self.accounts_list = None continue else: if self.accounts.is_here(): self.accounts_list.extend(self.page.iter_accounts()) has_account = True else: # We dont want to let has_account=False if we landed on an unknown page # it has to be the no_accounts page assert self.no_account.is_here() exc = None if not has_account: # if we landed twice on NoAccountPage, it means there is neither pro accounts nor pp accounts raise NoAccountsException() for account in list(self.accounts_list): if account.type == Account.TYPE_LOAN: # Loans details are present on another page so we create # a Loan object and remove the corresponding Account: self.location(account.url) loan = self.page.get_loan() loan.url = account.url self.loans_list.append(loan) self.accounts_list.remove(account) self.accounts_list.extend(self.loans_list) self.cards_list = [ acc for acc in self.accounts_list if acc.type == Account.TYPE_CARD ] if self.cards_list: self.go_cards_number(self.cards_list[0].url) if self.cards.is_here(): self.page.populate_cards_number(self.cards_list) # Cards without a number are not activated yet: for card in self.cards_list: if not card.number: self.accounts_list.remove(card) for account in self.accounts_list: if account.type not in (Account.TYPE_CARD, Account.TYPE_LOAN, Account.TYPE_CONSUMER_CREDIT, Account.TYPE_MORTGAGE, Account.TYPE_REVOLVING_CREDIT, Account.TYPE_LIFE_INSURANCE): account.iban = self.iban.go( webid=account._webid).get_iban() for card in self.cards_list: checking, = [ account for account in self.accounts_list if account.type == Account.TYPE_CHECKING and account.url in card.url ] card.parent = checking if exc: raise exc self.ownership_guesser() return self.accounts_list
def is_accounts(self): error_msg = CleanText('//span[@class="error_msg"]')(self.doc) if 'Vous ne disposez pas de compte consultable' in error_msg: raise NoAccountsException(error_msg)
def get_accounts_list(self): if not self.accounts_list: if self.currentSubBank is None: self.getCurrentSubBank() self.two_cards_page = None self.accounts_list = [] self.revolving_accounts = [] self.unavailablecards = [] self.cards_histo_available = [] self.cards_list = [] self.cards_list2 = [] # For some cards the validity information is only availaible on these 2 links self.cards_hist_available.go(subbank=self.currentSubBank) if self.cards_hist_available.is_here(): self.unavailablecards.extend(self.page.get_unavailable_cards()) for acc in self.page.iter_accounts(): acc._referer = self.cards_hist_available self.accounts_list.append(acc) self.cards_list.append(acc) self.cards_histo_available.append(acc.id) if not self.cards_list: self.cards_hist_available2.go(subbank=self.currentSubBank) if self.cards_hist_available2.is_here(): self.unavailablecards.extend( self.page.get_unavailable_cards()) for acc in self.page.iter_accounts(): acc._referer = self.cards_hist_available2 self.accounts_list.append(acc) self.cards_list.append(acc) self.cards_histo_available.append(acc.id) for acc in self.revolving_loan_list.stay_or_go( subbank=self.currentSubBank).iter_accounts(): self.accounts_list.append(acc) self.revolving_accounts.append(acc.label.lower()) # Handle cards on tiers page self.cards_activity.go(subbank=self.currentSubBank) companies = self.page.companies_link() if self.cards_activity.is_here() else \ [self.page] if self.is_new_website else [] for company in companies: # We need to return to the main page to avoid navigation error self.cards_activity.go(subbank=self.currentSubBank) page = self.open(company).page if isinstance( company, basestring) else company for card in page.iter_cards(): card2 = find_object(self.cards_list, id=card.id[:16]) if card2: # In order to keep the id of the card from the old space, we exchange the following values card._link_id = card2._link_id card._parent_id = card2._parent_id card.coming = card2.coming card._referer = card2._referer card._secondpage = card2._secondpage self.accounts_list.remove(card2) self.accounts_list.append(card) self.cards_list2.append(card) self.cards_list.extend(self.cards_list2) # Populate accounts from old website if not self.is_new_website: self.accounts.stay_or_go(subbank=self.currentSubBank) has_no_account = self.page.has_no_account() self.accounts_list.extend(self.page.iter_accounts()) self.iban.go(subbank=self.currentSubBank).fill_iban( self.accounts_list) self.por.go(subbank=self.currentSubBank).add_por_accounts( self.accounts_list) # Populate accounts from new website else: self.new_accounts.stay_or_go(subbank=self.currentSubBank) has_no_account = self.page.has_no_account() self.accounts_list.extend(self.page.iter_accounts()) self.iban.go(subbank=self.currentSubBank).fill_iban( self.accounts_list) self.por.go(subbank=self.currentSubBank).add_por_accounts( self.accounts_list) self.li.go(subbank=self.currentSubBank) self.accounts_list.extend(self.page.iter_li_accounts()) for acc in self.cards_list: if hasattr(acc, '_parent_id'): acc.parent = find_object(self.accounts_list, id=acc._parent_id) excluded_label = ['etalis', 'valorisation totale'] self.accounts_list = [ acc for acc in self.accounts_list if not any(w in acc.label.lower() for w in excluded_label) ] if has_no_account and not self.accounts_list: raise NoAccountsException(has_no_account) self.ownership_guesser() return self.accounts_list