def __init__(self, document, password, days=15, omit_sensitive_data=False, quiet=False, validator=SantanderValidator): if not quiet: print('[*] Santander Parser is starting...') self.validator = validator() self.account = Account(document=document, password=password) self.validate() self.account.bank = 'Santander' self.account.currency = 'R$' self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.balance = False self.transaction_days = days webdriver.DesiredCapabilities.PHANTOMJS['phantomjs.page.settings.userAgent'] = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36' webdriver.DesiredCapabilities.PHANTOMJS['phantomjs.page.customHeaders.Accept-Language'] = 'pt-BR' webdriver.DesiredCapabilities.PHANTOMJS['phantomjs.page.customHeaders.Connection'] = 'keep-alive' self.session = webdriver.PhantomJS() self.session.implicitly_wait(10) self.session.set_window_size(1920, 1080) self.wait = WebDriverWait(self.session, 10)
def __init__(self, card, omit_sensitive_data=False, quiet=False, dbc_username=None, dbc_password=None): if not quiet: print('[*] Ticket Parser is starting...') self.account = Account(None, card, account_type='card') self.account.currency = 'R$' self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.account.currency = 'R$' self.account.bank = 'Ticket' #self.dbc_username = dbc_username #self.dbc_password = dbc_password #self.dbc_client = deathbycaptcha.SocketClient(self.dbc_username, self.dbc_password) self.captcha = '' self.token = '' self.session = requests.Session() self.session.mount(self.api_endpoint, HTTPAdapter(max_retries=32,pool_connections=50, pool_maxsize=50)) self.session.headers.update({'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36'}) self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded'}) self.session.headers.update({'Referer': 'http://www.ticket.com.br/portal/consulta-de-saldo/'})
def __init__(self, branch, account, password, days=15, omit_sensitive_data=False, quiet=False, validator=ItauValidator): if not quiet: print('[*] Itaú Parser is starting...') number = account.split('-')[0] if '-' in account else account[:5] dac = account.split('-')[1] if '-' in account else account[-1] self.validator = validator() self.account = Account(branch=branch, number=number, password=password, dac=dac) self.validate() self.account.bank = 'Itaú' self.account.currency = 'R$' self.session = requests.Session() self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.encoding = '' self.ticket = '' self.transaction_days = days self.holder_code = '' self.session.mount(self.api_endpoint, HTTPAdapter(max_retries=32, pool_connections=50, pool_maxsize=50)) self.session.headers.update({'User-Agent': 'Apache-HttpClient/android/Nexus 5'}) self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded'}) self.session.headers.update({'Cookie2': '$Version=1'})
def __init__(self, branch, account, password, days, omit_sensitive_info=False, quiet=False): if not quiet: print('[*] Banco do Brasil Parser is starting...') self.account = Account(branch, account, password) self.account.bank = 'Banco do Brasil' self.account.currency = 'R$' self.days = days self.omit_sensitive_info = omit_sensitive_info self.quiet = quiet self.nick = 'NickRandom.{}'.format(randint(1000,99999)) self.idh = '' self.mci = '' self.segmento = '' self.session = requests.Session() self.session.mount(self.api_endpoint, HTTPAdapter(max_retries=32,pool_connections=50, pool_maxsize=50)) self.session.headers.update({'User-Agent': 'Android;Google Nexus 5 - 6.0.0 - API 23 - 1080x1920;Android;6.0;vbox86p-userdebug 6.0 MRA58K eng.buildbot.20160110.195928 test-keys;mov-android-app;6.14.0.1;en_US;cpu=0|clock=|ram=2052484 kB|espacoSDInterno=12.46 GB|isSmartphone=true|nfc=false|camera=true|cameraFrontal=true|root=true|reconhecimentoVoz=false|resolucao=1080_1776|densidade=3.0|'}) self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'})
def __init__(self, document, password, omit_sensitive_data=False, quiet=False): if not quiet: print('[*] Nubank Parser is starting...') self.account = Account(document, None, password, account_type='card') self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.account.currency = 'R$' self.account.bank = 'Nubank' self.session = requests.Session() self.session.mount( self.api_endpoint, HTTPAdapter(max_retries=32, pool_connections=50, pool_maxsize=50)) self.session.headers.update({ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36' }) self.session.headers.update({'Content-Type': 'application/json'}) self.session.headers.update( {'Referer': 'https://conta.nubank.com.br/'})
def __init__(self, branch, account, password, days=15, omit_sensitive_data=False, quiet=False, validator=ItauValidator): if not quiet: print('[*] Itaú Parser is starting...') number = account.split('-')[0] if '-' in account else account[:5] dac = account.split('-')[1] if '-' in account else account[-1] self.validator = validator() self.account = Account(branch=branch, number=number, password=password, dac=dac) self.validate() self.account.bank = 'Itaú' self.account.currency = 'R$' self.session = requests.Session() self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.encoding = '' self.ticket = '' self.transaction_days = days self.holder_code = '' self.session.mount( self.api_endpoint, HTTPAdapter(max_retries=32, pool_connections=50, pool_maxsize=50)) self.session.headers.update( {'User-Agent': 'Apache-HttpClient/android/Nexus 5'}) self.session.headers.update( {'Content-Type': 'application/x-www-form-urlencoded'}) self.session.headers.update({'Cookie2': '$Version=1'})
def __init__(self, card, document, omit_sensitive_data=False, quiet=False): if not quiet: print('[*] Sodexo Parser is starting...') self.account = Account(document, card, account_type='card') self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.account.currency = 'R$' self.account.bank = 'Sodexo' self.session = requests.Session() self.session.mount(self.api_endpoint, HTTPAdapter(max_retries=32,pool_connections=50, pool_maxsize=50)) self.session.headers.update({'User-Agent': 'Apache-HttpClient/android/Nexus 5'}) self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded'})
def __init__(self, branch, account, password, days=15, omit_sensitive_data=False, quiet=False): if not quiet: print('[*] Itaú Parser is starting...') self.account = Account(str(branch), str(account).split('-')[0], str(password), str(account).split('-')[1]) self.account.bank = 'Itaú' self.account.currency = 'R$' self.session = requests.Session() self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.encoding = '' self.ticket = '' self.transaction_days = days self.holder_code = '' self.eula_url = '' self.android_last_build = '' self.android_url = '' self.ios_last_build = '' self.ios_url = '' self.windowsphone_last_build = '' self.windowsphone_url = '' self.session.mount(self.api_endpoint, HTTPAdapter(max_retries=32,pool_connections=50, pool_maxsize=50)) self.session.headers.update({'User-Agent': 'Apache-HttpClient/android/Nexus 5'}) self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded'}) self.session.headers.update({'Cookie2': '$Version=1'})
class Ticket(object): api_endpoint = 'https://www.app.ticket.com.br/PMobileServer/Primeth' captcha_url = 'http://www.ticket.com.br/portal/stickyImg' login_url = 'http://www.ticket.com.br/portal/portalticket/dpages/service/captcha/getConsultCard.jsp' transactions_url = 'http://www.ticket.com.br/portal-web/consult-card/release/json' def __init__(self, card, omit_sensitive_data=False, quiet=False, dbc_username=None, dbc_password=None): if not quiet: print('[*] Ticket Parser is starting...') self.account = Account(None, card, account_type='card') self.account.currency = 'R$' self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.account.currency = 'R$' self.account.bank = 'Ticket' #self.dbc_username = dbc_username #self.dbc_password = dbc_password #self.dbc_client = deathbycaptcha.SocketClient(self.dbc_username, self.dbc_password) self.captcha = '' self.token = '' self.session = requests.Session() self.session.mount(self.api_endpoint, HTTPAdapter(max_retries=32,pool_connections=50, pool_maxsize=50)) self.session.headers.update({'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36'}) self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded'}) self.session.headers.update({'Referer': 'http://www.ticket.com.br/portal/consulta-de-saldo/'}) def get_unix_timestamp(self): return int((datetime.now(timezone.utc) + timedelta(days=3)).timestamp() * 1e3) def login(self): # We can just pretend to solve the captcha unixtm = self.get_unix_timestamp() path = '/tmp/.bankscraper_captcha_{}'.format(os.getpid()) r = self.session.get('{}?{}'.format(self.captcha_url, unixtm, stream=True)) if r.status_code == 200: with open(path, 'wb') as f: for chunk in r: f.write(chunk) captcha = '123456' if captcha: self.captcha = captcha r = self.session.post('{}?answer={}&card={}&d={}'.format(self.login_url, self.captcha, self.account.card, unixtm)) self.token = r.json()['token'] if not self.quiet: print('[*] Captcha decoded: {}'.format(self.captcha)) print('[*] Token: {}'.format(self.token)) return self.token def get_balance(self): payload = { 'card': self.account.card, 'answer': self.captcha, 'token': self.token, } r = self.session.post(self.transactions_url, data=payload) body = r.json() self.account.balance = Decimal(body['card']['balance']['value'].replace(',', '.')) print(self.account.get_balance()) return self.account.get_balance() def get_transactions(self): if not self.quiet: print('[*] Getting transactions...') print() payload = { 'card': self.account.card, 'answer': self.captcha, 'token': self.token, } r = self.session.post(self.transactions_url, data=payload) body = r.json() self.account.balance = Decimal(body['card']['balance']['value'].replace(',', '.')) self.parse_transactions(body['card']['release']) for trans in self.account.transactions: trans.print_info() return self.account.transactions def parse_transactions(self, transactions): tlist = [] for trans in transactions: try: t = Transaction(trans['description']) t.currency = 'R$' t.date = datetime.strptime(trans['date'], '%d/%m/%Y').date() t.value = Decimal(trans['value'].split()[-1].replace('.', '').replace(',', '.')) t.sign = '-' if trans['description'] != 'DISPONIB. DE CREDITO' else '+' t.raw = trans self.account.transactions.append(t) except: traceback.print_exc() continue return self.account.transactions
class Itau(object): app_id = 'kspf' app_version = '4.1.19' platform = 'android' platform_version = '6.0.1' platform_extra_version = '5.6.GA_v201508271451_r3' platform_model = 'Nexus 5' device_id = 12345678 user_id = 1234 api_endpoint = 'https://kms.itau.com.br/middleware/MWServlet' device_session_template = 'Modelo: {platform_model}|Operadora:|VersaoSO:{platform_version}|appIdCore:' def __init__(self, branch, account, password, days=15, omit_sensitive_data=False, quiet=False): if not quiet: print('[*] Itaú Parser is starting...') self.account = Account(str(branch), str(account).split('-')[0], str(password), str(account).split('-')[1]) self.account.bank = 'Itaú' self.account.currency = 'R$' self.session = requests.Session() self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.encoding = '' self.ticket = '' self.transaction_days = days self.holder_code = '' self.eula_url = '' self.android_last_build = '' self.android_url = '' self.ios_last_build = '' self.ios_url = '' self.windowsphone_last_build = '' self.windowsphone_url = '' self.session.mount(self.api_endpoint, HTTPAdapter(max_retries=32,pool_connections=50, pool_maxsize=50)) self.session.headers.update({'User-Agent': 'Apache-HttpClient/android/Nexus 5'}) self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded'}) self.session.headers.update({'Cookie2': '$Version=1'}) def json_recursive_loads(self, obj): obj = json.loads(obj) for k in obj.keys(): if type(obj[k]) == type(''): try: obj[k] = json.loads(obj[k]) except: pass for k in obj.keys(): if type(obj[k]) == type({}): for kk in obj[k].keys(): if type(obj[k][kk]) == type(''): try: obj[k][kk] = json.loads(obj[k][kk]) except: pass return obj def generate_timestamps(self): now1 = self.format_date_pd(datetime.now()) sleep(0.2) now2 = self.format_date_pd(datetime.now()) sleep(0.2) now3 = self.format_date_pd(datetime.now()) sleep(0.2) now4 = self.format_date_pd(datetime.now()) return {'d1': now1, 'd2': now2, 'd3': now3, 'd4': now4} def build_device_session(self, extra): msg = self.device_session_template.format(platform_model=self.platform_model, platform_version=self.platform_version) msg = msg + '|' + extra return msg def format_date_pd(self, dtobj): return dtobj.strftime('%-m/%-d/%Y %-H-%-M-%-S-%f')[:-3] def post(self, payload): return self.session.post(self.api_endpoint, data=payload) def login(self): if not self.quiet: print('[*] Logging in to {} {}-{}'.format(self.account.branch,self.account.number,self.account.dac)) payload = { 'Guid': '7C9C0508-6EFD-47B6-9DBA-5E4B1205D560', 'DeviceId': self.device_id, 'UserId': self.user_id, 'Params': 'MOBILECORE_JSON_SMART_ITAUPF', 'platform': 'android', 'appID': self.app_id, 'appver': self.app_version, 'IPCliente': '', 'Ticket': '', 'channel': 'rc', 'serviceID': 'srvJCoreRuntime', 'cacheid': '', 'platformver': self.platform_extra_version, 'DadosSessaoDevice': 'Modelo:Nexus 5|Operadora:|VersaoSO:6.0.1|appIdCore:' } r = self.post(payload) obj = self.json_recursive_loads(r.content.decode()) if obj['opstatus'] == 0: if not self.quiet: print('[+] Login successful!') else: raise GeneralException('Something went wrong...', request=r) self.account.app = App('Itaú') self.account.app.eula_url = obj['Dados']['home_config']['link_termos_uso'] for o in obj['Dados']['app_config']['plataforma']: if o['nome'] == 'android': self.account.app.platform['android']['version'] = o['build_number_atual'] self.account.app.platform['android']['url'] = o['url_loja:'] elif o['nome'] == 'iphone': self.account.app.platform['ios']['version'] = o['build_number_atual'] self.account.app.platform['ios']['url'] = o['url_loja:'] elif o['nome'] == 'windowsphone': self.account.app.platform['windowsphone']['version'] = o['build_number_8'] self.account.app.platform['windowsphone']['url']= o['url_loja:'] if not self.quiet: print() self.account.app.print_info() print() now = datetime.now() if not self.quiet: print('[*] Getting account information...') t = self.generate_timestamps() payload = { 'DeviceId': self.device_id, 'UserId': self.user_id, 'UA': 'AppItauSmartPF:R1;{version};{platform};{platform_version};{platform_model};{{F001;}}'.format(version=self.app_version, platform=self.platform, platform_version=self.platform_version,platform_model=self.platform_model), 'Agencia': self.account.branch, 'Dac': self.account.dac, 'platform': self.platform, 'Tecnologia': 4, 'Sv': '', 'appID': self.app_id, 'appver': self.app_version, 'ListaMenu': '', 'Conta': self.account.number, 'channel': 'rc', 'serviceID': 'srvJLogin', 'cacheid': '', 'Senha': self.account.password, 'platformver': self.platform_extra_version, 'DadosSessaoDevice': self.build_device_session('root:X|PD:{d1},{d2}H'.format(**t)) } r = self.post(payload) obj = self.json_recursive_loads(r.content.decode()) if obj['opstatus'] == 0: pass else: raise GeneralException('Something went wrong...', request=r) try: if int(obj['Dados']['RESPOSTA']['DADOS']['CODIGO']) == 31 : raise AnotherActiveSessionException(obj['Dados']['RESPOSTA']['DADOS']['MENSAGEM']) elif int(obj['Dados']['RESPOSTA']['DADOS']['CODIGO']) == 30: raise MaintenanceException(obj['Dados']['RESPOSTA']['DADOS']['MENSAGEM']) except KeyError: pass self.encoding = obj['Dados']['?xml']['@encoding'] self.account.owner = Owner(obj['Dados']['RESPOSTA']['DADOS']['NOME_CORRENTISTA'].strip().title()) self.account.segment = obj['Dados']['RESPOSTA']['DADOS']['SEGMENTO'].strip() self.account.type = 'Física' if obj['Dados']['RESPOSTA']['DADOS']['PESSOA'] == 'F' else 'Jurídica' self.account.owner.document = obj['Dados']['RESPOSTA']['DADOS']['CPF_CNPJ_CLIENTE'].strip() self.account.owner.birthday = datetime.strptime(obj['Dados']['RESPOSTA']['DADOS']['DT8_GB07'], '%d%m%Y') self.holder_code = obj['Dados']['RESPOSTA']['DADOS']['TITULARIDADE'] self.ticket = obj['Ticket'] if not self.quiet: print() self.account.print_info() print() self.account.owner.print_info() print() def logout(self): if not self.quiet: print('[*] Logging out...') t = self.generate_timestamps() payload = { 'DeviceId': self.device_id, 'UserId': self.user_id, 'UA': 'AppItauSmartPF:R1;{version};{platform};{platform_version};{platform_model};{{F001;}}'.format(version=self.app_version, platform=self.platform, platform_version=self.platform_version,platform_model=self.platform_model), 'ServiceName': 'SAIR', 'Sv': '', 'appID': self.app_id, 'appver': self.app_version, 'IPCliente': '', 'Ticket': self.ticket, 'channel': 'rc', 'serviceID': 'srvJGenerico', 'platformver': self.platform_extra_version, 'DadosSessaoDevice': 'PD:{d1},{d2},{d3},{d4}|AGC_SAIR:{ag}{ac}{dac}'.format(ag=self.account.branch,ac=self.account.number,dac=self.account.dac,**t), 'Lista': '' } r = self.post(payload) obj = self.json_recursive_loads(r.content.decode()) if obj['opstatus'] == 0: if not self.quiet: print('[+] Logged out succesfully!') else: raise GeneralException('Something went wrong...', request=r) def post_login_warmup(self): if not self.quiet: print('[*] Warming up...') t = self.generate_timestamps() payload = { 'DeviceId': self.device_id, 'UserId': self.user_id, 'UA': 'AppItauSmartPF:R1;{version};{platform};{platform_version};{platform_model};{{F001;}}'.format(version=self.app_version, platform=self.platform, platform_version=self.platform_version,platform_model=self.platform_model), 'ServiceName': 'CSTA_POR_TIPO', 'Sv': '', 'appID': self.app_id, 'appver': self.app_version, 'IPCliente': '', 'Ticket': self.ticket, 'channel': 'rc', 'serviceID': 'srvJGenerico', 'platformver': self.platform_extra_version, 'DadosSessaoDevice': 'PD:{d1},{d2},{d3},{d4}|AGC_CSTA_PORT_TIPO:{ag}{ac}{dac}'.format(ag=self.account.branch,ac=self.account.number,dac=self.account.dac,**t), 'Lista': 'EMHUOYKIRBVPRCMNEWZ60XJPRNY|PF |352136067883617|00012' } r = self.post(payload) obj = self.json_recursive_loads(r.content.decode()) if obj['opstatus'] == 0: pass else: raise GeneralException('Something went wrong...') payload = { 'appID': self.app_id, 'appver': self.app_version, 'Ticket': self.ticket, 'channel': 'rc', 'serviceID': 'srvJMenu', 'platformver': self.platform_extra_version, } r = self.post(payload) obj = self.json_recursive_loads(r.content.decode()) if obj['opstatus'] == 0: pass else: raise GeneralException('Something went wrong...', request=r) payload = { 'Guid': '7C9C0508-6EFD-47B6-9DBA-5E4B1205D560', 'DeviceId': self.device_id, 'UserId': self.user_id, 'Params': self.ticket, 'appID': self.app_id, 'appver': self.app_version, 'IPCliente': '', 'Ticket': self.ticket, 'channel': 'rc', 'serviceID': 'srvJCoreRuntime', 'platformver': self.platform_extra_version, 'DadosSessaoDevice': self.build_device_session('root:X') } r = self.post(payload) obj = self.json_recursive_loads(r.content.decode()) if obj['opstatus'] == 0: pass else: raise GeneralException('Something went wrong...', request=r) payload = { 'Guid': '7C9C0508-6EFD-47B6-9DBA-5E4B1205D560', 'DeviceId': self.device_id, 'UserId': self.user_id, 'Params': 'SMARTPHONE_PF_TOKEN_WEBVIEW', 'appID': self.app_id, 'appver': self.app_version, 'IPCliente': '', 'Ticket': self.ticket, 'channel': 'rc', 'serviceID': 'srvJGenerico', 'platformver': self.platform_extra_version, 'DadosSessaoDevice': self.build_device_session('root:X') } r = self.post(payload) obj = self.json_recursive_loads(r.content.decode()) if obj['opstatus'] == 0: pass else: raise GeneralException('Something went wrong...', request=r) payload = { 'HolderCodeType': 1, 'AccountNumber': self.account.number, 'Dac': self.account.dac, 'Type': 0, 'BranchNumber': self.account.branch, 'HolderCode': self.holder_code, 'appID': self.app_id, 'appver': self.app_version, 'IPCliente': '', 'Ticket': self.ticket, 'channel': 'rc', 'serviceID': 'srvJGetUserInfo', 'platformver': self.platform_extra_version, } r = self.post(payload) obj = self.json_recursive_loads(r.content.decode()) if obj['opstatus'] == 0: pass else: raise GeneralException('Something went wrong...', request=r) def get_balance(self): if not self.quiet: print('[*] Getting transactions...') t = self.generate_timestamps() payload = { 'DeviceId': self.device_id, 'UserId': self.user_id, 'UA': 'AppItauSmartPF:R1;{version};{platform};{platform_version};{platform_model};{{F001;}}'.format(version=self.app_version, platform=self.platform, platform_version=self.platform_version,platform_model=self.platform_model), 'ServiceName': 'EXTRATO', 'Sv': '', 'appID': self.app_id, 'appver': self.app_version, 'IPCliente': '', 'Ticket': self.ticket, 'channel': 'rc', 'cacheid': '', 'platform': self.platform, 'serviceID': 'srvJGenerico', 'platformver': self.platform_extra_version, 'DadosSessaoDevice': 'PD:{d1},{d2},{d3},{d4}|AGC_EXTRATO:{ag}{ac}{dac}'.format(ag=self.account.branch,ac=self.account.number,dac=self.account.dac,**t), 'Lista': '{}|V|CC|E|1'.format(self.transaction_days) } r = self.post(payload) obj = self.json_recursive_loads(r.content.decode()) if obj['opstatus'] == 0: pass else: raise GeneralException('Something went wrong...', request=r) for o in obj['Dados']['RESPOSTA']['DADOS']['DADOSEXTRATO']['SALDORESUMIDO']['ITEM']: if o['NOME'] == 'SALDODISPSAQUERESUMO': self.account.balance = Decimal(o['VALOR'].replace('.', '').replace(',', '.')) self.account.sign = '-' if o['SINAL'] == 'D' else '+' elif o['NOME'] == 'LIMITELISRESUMO': self.account.overdraft = Decimal(o['VALOR'].replace('.', '').replace(',', '.')) print(self.account.get_balance()) return self.account.get_balance() def get_transactions(self): if not self.quiet: print('[*] Getting transactions...') t = self.generate_timestamps() payload = { 'DeviceId': self.device_id, 'UserId': self.user_id, 'UA': 'AppItauSmartPF:R1;{version};{platform};{platform_version};{platform_model};{{F001;}}'.format(version=self.app_version, platform=self.platform, platform_version=self.platform_version,platform_model=self.platform_model), 'ServiceName': 'EXTRATO', 'Sv': '', 'appID': self.app_id, 'appver': self.app_version, 'IPCliente': '', 'Ticket': self.ticket, 'channel': 'rc', 'cacheid': '', 'platform': self.platform, 'serviceID': 'srvJGenerico', 'platformver': self.platform_extra_version, 'DadosSessaoDevice': 'PD:{d1},{d2},{d3},{d4}|AGC_EXTRATO:{ag}{ac}{dac}'.format(ag=self.account.branch,ac=self.account.number,dac=self.account.dac, **t), 'Lista': '{}|V|CC|E|1'.format(self.transaction_days) } r = self.post(payload) obj = self.json_recursive_loads(r.content.decode()) if obj['opstatus'] == 0: pass else: raise GeneralException('Something went wrong...', request=r) self.parse_transactions(obj['Dados']['RESPOSTA']['DADOS']['DADOSEXTRATO']['EXTRATO']['MOVIMENT']) for transaction in self.account.transactions: transaction.print_info() return self.account.transactions def parse_transactions(self, transactions): tlist = [] for trans in transactions: try: if self.omit_sensitive_data: if trans['HISTOR'] not in ['SALDO', 'S A L D O'] and 'REMUNERACAO' not in trans['HISTOR'] and 'SALDO' not in trans['HISTOR'] and 'SDO CTA' not in trans['HISTOR']: t = Transaction(trans['HISTOR']) t.value = Decimal(trans['VAL2'].replace('.', '').replace(',', '.')) t.sign = '-' if trans['DC2'] == 'D' else '+' t.date = self.parse_date(trans['DT8']).date() t.currency = 'R$' t.raw = trans self.account.transactions.append(t) else: t = Transaction(trans['HISTOR']) t.value = Decimal(trans['VAL2'].replace('.', '').replace(',', '.')) t.sign = '-' if trans['DC2'] == 'D' else '+' t.date = self.parse_date(trans['DT8']).date() t.currency = 'R$' t.raw = trans self.account.transactions.append(t) except: traceback.print_exc() pass return self.account.transactions def parse_date(self, d): day = d.split('/')[0] month = d.split('/')[1] year = date.today().year if int(month) > date.today().month: year = date.today().year - 1 d = '{}/{}/{}'.format(day, month, year) return datetime.strptime(d, '%d/%m/%Y')
class Sodexo(object): api_endpoint = 'https://www.app.sodexo.com.br/PMobileServer/Primeth' def __init__(self, card, document, omit_sensitive_data=False, quiet=False): if not quiet: print('[*] Sodexo Parser is starting...') self.account = Account(document, card, account_type='card') self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.account.currency = 'R$' self.account.bank = 'Sodexo' self.session = requests.Session() self.session.mount(self.api_endpoint, HTTPAdapter(max_retries=32,pool_connections=50, pool_maxsize=50)) self.session.headers.update({'User-Agent': 'Apache-HttpClient/android/Nexus 5'}) self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded'}) def get_balance(self): payload = { 'th': 'thsaldo', 'cardNumber': self.account.card, 'document': self.account.document } r = self.session.post(self.api_endpoint, data=payload) body = r.json() self.account.service_name = body['serviceName'] self.account.status = body['cardStatus'] self.account.company = body['companyName'] self.account.owner = Owner(body['name']) self.account.balance = Decimal(body['balanceAmount'].split()[-1].replace('.', '').replace(',', '.')) if not self.quiet: print() self.account.print_info() print() print(self.account.get_balance()) return self.account.get_balance() def get_transactions(self): if not self.quiet: print('[*] Getting transactions...') payload = { 'th': 'thsaldo', 'cardNumber': self.account.card, 'document': self.account.document } r = self.session.post(self.api_endpoint, data=payload) body = r.json() self.account.service_name = body['serviceName'] self.account.status = body['cardStatus'] self.account.company = body['companyName'] self.account.owner = Owner(body['name']) self.account.balance = body['balanceAmount'] if not self.quiet: print() self.account.print_info() print() self.parse_transactions(body['transactions']) for trans in self.account.transactions: trans.print_info() return self.account.transactions def parse_transactions(self, transactions): tlist = [] for trans in transactions: try: t = Transaction(trans['history']) t.id = trans['authorizationNumber'] t.currency = 'R$' t.date = datetime.strptime(trans['date'], '%d/%m/%Y').date() t.value = Decimal(trans['value'].split()[-1].replace('.', '').replace(',', '.')) t.sign = '-' if trans['type'].endswith('bito') else '+' t.raw = trans self.account.transactions.append(t) except: traceback.print_exc() continue return self.account.transactions
class Santander(BankScraper): api_endpoint = 'https://www.santandernet.com.br/' first_page_url = 'https://www.santander.com.br/' logout_url_1 = 'https://www.santandernet.com.br/IBPF_Logout.asp' logout_url_2 = 'https://www.santandernet.com.br/logout.asp' login_url1 = 'https://www.santandernet.com.br/' login_url2 = 'https://www.santandernet.com.br/IBPF/NMSDLoginAsIs.asp' def __init__(self, document, password, days=15, omit_sensitive_data=False, quiet=False, validator=SantanderValidator): if not quiet: print('[*] Santander Parser is starting...') self.validator = validator() self.account = Account(document=document, password=password) self.validate() self.account.bank = 'Santander' self.account.currency = 'R$' self.omit_sensitive_data = omit_sensitive_data self.quiet = quiet self.balance = False self.transaction_days = days webdriver.DesiredCapabilities.PHANTOMJS['phantomjs.page.settings.userAgent'] = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36' webdriver.DesiredCapabilities.PHANTOMJS['phantomjs.page.customHeaders.Accept-Language'] = 'pt-BR' webdriver.DesiredCapabilities.PHANTOMJS['phantomjs.page.customHeaders.Connection'] = 'keep-alive' self.session = webdriver.PhantomJS() self.session.implicitly_wait(10) self.session.set_window_size(1920, 1080) self.wait = WebDriverWait(self.session, 10) def login(self): if not self.quiet: print('[*] Logging in as {}'.format(self.account.document)) try: self.session.get(self.first_page_url) elem = self.wait.until(EC.visibility_of_element_located((By.NAME, 'txtCPF'))) elem.send_keys(self.account.document) elem.send_keys(Keys.ENTER) sleep(3) self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.NAME, 'Principal')))) self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.NAME, 'MainFrame')))) if 'iframeContrato' in self.session.page_source: print('[-] You need to manually accept an usage agreement') exit(1) elem = self.wait.until(EC.visibility_of_element_located((By.ID, 'txtSenha'))) elem.send_keys(self.account.password) elem.send_keys(Keys.ENTER) self.session.switch_to.default_content() self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.NAME, 'Principal')))) self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.NAME, 'Corpo')))) ola = self.session.find_element_by_id('ola') soup = bs(ola.get_attribute('innerHTML')) table = soup.find('table') self.account.owner = Owner(table.find_all('td')[0].find('strong').text.strip()) self.account.owner.document = self.account.document self.account.branch = table.find_all('td')[1].text.split()[1] self.account.number = ''.join(table.find_all('td')[1].text.split()[3].split('.')[:2]) self.account.dac = table.find_all('td')[1].text.split()[3].split('.')[-1] self.account.print_info() self.account.owner.print_info() except UnexpectedAlertPresentException: print('[-] Login failed, invalid credentials') exit(1) except Exception: traceback.print_exc() self.session.save_screenshot('/tmp/screenie.png') exit(1) def logout(self): self.session.switch_to.default_content() self.session.get(self.logout_url_1) self.session.get(self.logout_url_2) def get_balance(self): # All on the same page self.balance = True self.get_transactions() def get_transactions(self): if not self.quiet: print('[*] Getting transactions...') self.session.switch_to.frame(self.session.find_element_by_name('iframePainel')) elem = self.session.find_element_by_id('extrato') select = Select(elem.find_element_by_name('cboSelectPeriodoExtrato')) select.select_by_value(self.transaction_days) elem.find_element_by_class_name('botao').click() self.session.switch_to.default_content() self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.NAME, 'Principal')))) self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.NAME, 'Corpo')))) self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.NAME, 'iframePrinc')))) self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.ID, 'extrato')))) elem = self.session.find_elements_by_class_name('lista') soup = bs(elem[0].get_attribute('innerHTML')) if not self.balance: transactions = self.parse_transactions(soup.find_all('tr')) if not self.quiet: for trans in transactions: trans.print_info() soup = bs(elem[1].get_attribute('innerHTML')) for tr in soup.find_all('tr'): if tr.find_all('td')[0].text.strip() == 'A - Saldo de ContaMax': self.account.balance = Decimal(tr.find_all('td')[1].text.strip().replace('-', '').replace('.', '').replace(',', '.')) self.account.sign = '-' if '-' in tr.find_all('td')[1].text.strip() else '+' elif tr.find_all('td')[0].text.strip().startswith('D -'): self.account.overdraft = Decimal(tr.find_all('td')[1].text.strip().replace('-', '').replace('.', '').replace(',', '.')) self.session.switch_to.default_content() self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.NAME, 'Principal')))) self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.NAME, 'Corpo')))) self.session.switch_to.frame(self.wait.until(EC.visibility_of_element_located((By.ID, 'ifr_sal')))) elem = self.session.find_element_by_id('tblSaldos') soup = bs(elem.get_attribute('innerHTML')) t = soup.find('div', {'id': 'CPVendedora'}) self.account.personal_credit = Decimal(t.find_all('td')[1].text.strip().replace('-', '').replace('.', '').replace(',', '.')) def parse_transactions(self, transactions): for tr in transactions: if tr.find('th'): continue description = tr.find_all('td')[2].text.strip() if description.startswith('SALDO'): continue t = Transaction(description) t.date = datetime.strptime(tr.find_all('td')[0].text.strip(), '%d/%m/%Y') t.id = tr.find_all('td')[3].text.strip() v = tr.find_all('td')[5].text.strip() t.sign = '-' if '-' in v else '+' t.value = Decimal(v.replace('-', '').replace('.', '').replace(',', '.')) self.account.transactions.append(t) return self.account.transactions
class BB(BankScraper): api_endpoint = 'https://mobi.bb.com.br/mov-centralizador/' idDispositivo = '000000000000000' ida = '00000000000000000000000000000000' hash_url = 'https://mobi.bb.com.br/mov-centralizador/hash' login_url = 'https://mobi.bb.com.br/mov-centralizador/servico/ServicoLogin/login' balance_url = 'https://mobi.bb.com.br/mov-centralizador/servico/ServicoSaldo/saldo' transactions_url = 'https://mobi.bb.com.br/mov-centralizador/tela/ExtratoDeContaCorrente/extrato' post_login_warmup_url1 = 'https://mobi.bb.com.br/mov-centralizador/servico/ServicoVersionamento/servicosVersionados' post_login_warmup_url2 = 'https://mobi.bb.com.br/mov-centralizador/servico/ServicoVersaoCentralizador/versaoDaAplicacaoWeb' post_login_warmup_url3 = 'https://mobi.bb.com.br/mov-centralizador/servico/ServicoMenuPersonalizado/menuPersonalizado' post_login_warmup_url4 = 'https://mobi.bb.com.br/mov-centralizador/servico/ServicoMenuTransacoesFavoritas/menuTransacoesFavoritas' def __init__(self, branch, account, password, days, omit_sensitive_info=False, quiet=False): if not quiet: print('[*] Banco do Brasil Parser is starting...') self.account = Account(branch, account, password) self.account.bank = 'Banco do Brasil' self.account.currency = 'R$' self.days = days self.omit_sensitive_info = omit_sensitive_info self.quiet = quiet self.nick = 'NickRandom.{}'.format(randint(1000,99999)) self.idh = '' self.mci = '' self.segmento = '' self.session = requests.Session() self.session.mount(self.api_endpoint, HTTPAdapter(max_retries=32,pool_connections=50, pool_maxsize=50)) self.session.headers.update({'User-Agent': 'Android;Google Nexus 5 - 6.0.0 - API 23 - 1080x1920;Android;6.0;vbox86p-userdebug 6.0 MRA58K eng.buildbot.20160110.195928 test-keys;mov-android-app;6.14.0.1;en_US;cpu=0|clock=|ram=2052484 kB|espacoSDInterno=12.46 GB|isSmartphone=true|nfc=false|camera=true|cameraFrontal=true|root=true|reconhecimentoVoz=false|resolucao=1080_1776|densidade=3.0|'}) self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'}) def login(self): payload = { 'hash': '', 'idh': '', 'id': self.ida, 'idDispositivo': self.idDispositivo, 'apelido': self.nick } r = self.session.post(self.hash_url, data=payload) self.idh = r.content payload = { 'idh': self.idh, 'senhaConta': self.account.password, 'apelido': self.nick, 'dependenciaOrigem': self.account.branch, 'numeroContratoOrigem': self.account.number, 'idRegistroNotificacao': '', 'idDispositivo': self.idDispositivo, 'titularidade': 1 } r = self.session.post(self.login_url, data=payload) j = r.json() self.mci = j['login']['mci'] self.account.type = j['login']['segmento'] self.account.owner = Owner(j['login']['nomeCliente']) if not self.quiet: print() self.account.print_info() self.account.owner.print_info() print() def post_login_warmup(self): payload = { 'servico/ServicoVersionamento/servicosVersionados:': '', 'idh': self.idh, 'idDispositivo': self.idDispositivo, 'apelido': self.nick } for url in [post_login_warmup_url1, post_login_warmup_url2, post_login_warmup_url3, post_login_warmup_url4]: self.session.post(url, data=payload) def get_balance(self): payload = { 'servico/ServicoSaldo/saldo': '', 'idh': self.idh, 'idDispositivo': self.idDispositivo, 'apelido': self.nick } r = self.session.post(self.balance_url, data=payload) j = r.json() jr = j['servicoSaldo']['saldo'] self.account.balance = Decimal(jr.split()[0].replace('.', '').replace(',', '.')) * -1 if jr.split()[-1] == 'D' else float(jr.split()[0].replace('.', '').replace(',', '.')) print(self.account.get_balance()) def get_transactions(self): payload = { 'abrangencia': 8, 'idh': self.idh, 'idDispositivo': self.idDispositivo, 'apelido': self.nick } r = self.session.post(self.transactions_url, data=payload) j = r.json() jr = j['conteiner']['telas'][0]['sessoes'] for s in jr: if s['TIPO'] == 'sessao' and s.get('cabecalho'): if s['cabecalho'].startswith('M') and 'ncia:' in s['cabecalho']: month = s['cabecalho'].split()[-3:] for tt in s['celulas']: if tt['TIPO'] == 'celula': if len(tt['componentes']) == 3 and tt['componentes'][0]['componentes'][0]['texto'] != 'Dia': t = Transaction(tt['componentes'][1]['componentes'][0]['texto']) t.date = self.parse_date(tt['componentes'][0]['componentes'][0]['texto'], month[0], month[2]).date() t.value = Decimal(tt['componentes'][2]['componentes'][0]['texto'].split()[0].replace('.', '').replace(',', '.')) t.sign = '-' if tt['componentes'][2]['componentes'][0]['texto'].split()[-1] == 'D' else '+' t.currency = 'R$' t.raw = tt['componentes'] self.account.transactions.append(t) else: continue elif s['cabecalho'].startswith('Informa') and s['cabecalho'].endswith('es adicionais'): for tt in s['celulas']: if tt['TIPO'] == 'celula': print(tt['componentes'][0]['componentes'][0]['texto']) if tt['componentes'][0]['componentes'][0]['texto'] == 'Juros': self.account.interest = Decimal(tt['componentes'][1]['componentes'][0]['texto'].split()[-1].replace('.', '').replace(',', '.')) for trans in self.account.transactions: trans.print_info() return self.account.transactions def parse_date(self, day, month, year): m2n = { 'Janeiro': 1, 'Fevereiro': 2, 'Marco': 3, 'Março': 3, 'Abril': 4, 'Maio': 5, 'Junho': 6, 'Julho': 7, 'Agosto': 8, 'Setembro': 9, 'Outubro': 10, 'Novembro': 11, 'Dezembro': 12 } return datetime.strptime('{}/{}/{}'.format(day, m2n[month], year), '%d/%m/%Y')