Open henriquebastos opened 6 years ago
Adicionei "from itauscraper.pages import Page" no topo e rodei
(tools3) gabriel@localhost:/tmp$ xvfb-run python test.py
['chromedriver', '--port=53297']
Traceback (most recent call last):
File "test.py", line 131, in <module>
itau.get()
AttributeError: 'ItauHome' object has no attribute 'get'
(tools3) gabriel@localhost:/tmp$ pip freeze | grep itau
itauscraper==1.0
EDIT:
Adicionei:
def get(self):
self.driver.get(self.URL)
Funcionou no Ubuntu com:
1 - pip install nos pacotes
itauscraper==1.0
selenium==3.13.0
2 - download do chrome driver https://sites.google.com/a/chromium.org/chromedriver/getting-started copiei o executável para o mesmo diretório do codigo
3 - Precisei alterar o código: i) adicionei o método get no ItauHome
def get(self):
self.driver.get(self.URL)
ii) import do Page:
from itauscraper.pages import Page
iii) Informar o path do executável do chrome na inicialização do browser:
browser = webdriver.Chrome('/home/roger/itau/chromedriver', chrome_options=options)
iv) Comentado a linha de indentificação do nome
# itau.identify('MEUNOME')
Valeu
Legal, @gmonnerat! Esse rascunho é pra ser rodado isolado com o selenium.
@huogerac Achei curiosa a necessidade de especificar o path
do chromedriver. Qual seu OS?
Não resisti e refiz o rascunho pra dar um leve tapa na organização:
from pathlib import Path
from contextlib import contextmanager
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class Chrome(webdriver.Chrome):
def __init__(self, *args, **kwargs):
options = webdriver.ChromeOptions()
options.add_argument('--disable-web-security')
options.add_experimental_option(
"prefs", {
'download.default_directory' : str(Path().absolute()),
}
)
return super().__init__(chrome_options=options)
def wait_until(self, method, timeout=10, interval=1):
return WebDriverWait(self, timeout, interval).until(method)
def element(self, locator):
return self.find_element(*locator)
@contextmanager
def frame(self, name):
self.switch_to.frame(name)
yield
self.switch_to.default_content()
@contextmanager
def tab(self):
current = self.current_window_handle
# open new tab
self.execute_script('window.open("about:blank", "_blank");')
# switch to new tab
self.switch_to_window(self.window_handles[-1])
yield
# close tab
self.close()
# switch back to previous tab
self.switch_to_window(current)
def wait_downloads(self):
self.get("chrome://downloads/")
cmd = """
var items = downloads.Manager.get().items_;
if (items.every(e => e.state === "COMPLETE"))
return items.map(e => e.file_path);
"""
# waits for all the files to be completed and returns the paths
return self.wait_until(lambda d: d.execute_script(cmd), timeout=120)
def ID(value):
return By.ID, value
def css(value):
return By.CSS_SELECTOR, value
def xpath(value):
return By.XPATH, value
def link_contains(value):
return By.PARTIAL_LINK_TEXT, value
present = EC.presence_of_element_located
invisible = EC.invisibility_of_element_located
def js_href(el):
return el.get_attribute('href').partition(':')[-1]
class ItauHome:
URL = 'https://www.itau.com.br/'
def __init__(self, driver):
self.driver = driver
def login(self, agencia, conta, nome, password):
# 1. Acessa o site.
self.driver.get(self.URL)
# 2. Preenche agência e conta.
el = self.driver.element
el(ID('campo_agencia')).send_keys(agencia)
el(ID('campo_conta')).send_keys(conta)
el(css('a.btnSubmit')).click()
# 3. Identifica o titular.
titular = self.driver.wait_until(present(link_contains(nome)))
self.driver.execute_script(js_href(titular))
# 4. Clica a senha no teclado virtual.
submit = self.driver.wait_until(present(link_contains('acessar')))
self.driver.wait_until(invisible(css('div.blockUI.blockOverlay')))
for digit in password:
self.driver.element(link_contains(digit)).click()
submit.click()
# 5. Aguarda carregar o dashboard.
self.driver.wait_until(present(xpath("//a[contains(text(),'Saldo e extrato')]")))
def go_to_extrato(self):
menu = self.driver.wait_until(present(xpath("//a[contains(text(),'Saldo e extrato')]")))
self.driver.execute_script(js_href(menu))
def go_to_ofx(self):
self.go_to_extrato()
with self.driver.frame('CORPO'):
menu = self.driver.wait_until(present(xpath("//a[contains(text(),'Salvar em outros formatos')]")))
self.driver.execute_script(js_href(menu))
def salvar_ofx(self, dia, mes, ano):
with self.driver.frame('CORPO'):
el = self.driver.element
el(ID('Dia')).send_keys(f'{dia:02}{mes:02}{ano}')
el(css("input[value='OFX']")).click()
el(xpath("//a[img[@alt='Continuar']]")).click()
with self.driver.tab():
paths = self.driver.wait_downloads()
return paths
if __name__ == '__main__':
itau = ItauHome(Chrome())
itau.login('1234', '123456', 'MEUNOME', '000000')
itau.go_to_ofx()
print(itau.salvar_ofx(1, 1, 2018))
@henriquebastos, não sei se o caso do @huogerac é mesmo caso que o meu, mas no Debian eu fiz o download e copiei o binario para /usr/bin
. Sem isso ele não encontra no meu $PATH e vai acontecer esse erro:
(tools3) gabriel@localhost:~$ xvfb-run python test.py
['chromedriver', '--port=48779']
Traceback (most recent call last):
File "/home/gabriel/.pyenv/versions/tools3/lib/python3.6/site-packages/selenium/webdriver/common/service.py", line 77, in start
stdin=PIPE)
File "/home/gabriel/.pyenv/versions/3.6.3/lib/python3.6/subprocess.py", line 709, in __init__
restore_signals, start_new_session)
File "/home/gabriel/.pyenv/versions/3.6.3/lib/python3.6/subprocess.py", line 1344, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'chromedriver': 'chromedriver'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 130, in <module>
browser = webdriver.Chrome(chrome_options=options)
File "/home/gabriel/.pyenv/versions/tools3/lib/python3.6/site-packages/selenium/webdriver/chrome/webdriver.py", line 68, in __init__
self.service.start()
File "/home/gabriel/.pyenv/versions/tools3/lib/python3.6/site-packages/selenium/webdriver/common/service.py", line 84, in start
os.path.basename(self.path), self.start_error_message)
selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home
Talvez definindo o path
do chromedriver no $PATH funcione também, tipo:
PATH=$PATH:/home/gabriel/itau/chromedriver python test.py
@henriquebastos, valeu pelo refactoring no rascunho!
No meu caso, minha não é conta conjunta, então eu não preciso selecionar o titular, aparece apenas Ola Gabriel
.
Alterei o código para suportar os dois e por padrão, selecionar o titular.
--- test2.py.bak 2018-07-26 14:21:27.436270557 +0000
+++ test2.py 2018-07-26 14:23:42.748867087 +0000
@@ -86,7 +86,7 @@
def __init__(self, driver):
self.driver = driver
- def login(self, agencia, conta, nome, password):
+ def login(self, agencia, conta, nome, password, conta_conjunta=True):
# 1. Acessa o site.
self.driver.get(self.URL)
@@ -96,9 +96,16 @@
el(ID('campo_conta')).send_keys(conta)
el(css('a.btnSubmit')).click()
- # 3. Identifica o titular.
- titular = self.driver.wait_until(present(link_contains(nome)))
- self.driver.execute_script(js_href(titular))
+ if conta_conjunta:
+ # 3. Identifica o titular
+ titular = self.driver.wait_until(present(link_contains(nome)))
+ self.driver.execute_script(js_href(toitular))
+ else:
+ # 3. O titular é selecionado automaticamente e
+ # a página é redirecionada para o teclado virtual
+ self.driver.wait_until(present(
+ xpath('//strong[text()="{}"]'.format(nome))
+ ))
# 4. Clica a senha no teclado virtual.
submit = self.driver.wait_until(present(link_contains('acessar')))
@@ -138,6 +145,6 @@
if __name__ == '__main__':
itau = ItauHome(Chrome())
- itau.login('1234', '123456', 'MEUNOME', '000000')
+ itau.login('1234', '123456', 'MEUNOME', '000000', False)
itau.go_to_ofx()
print(itau.salvar_ofx(1, 1, 2018))
Estou rodando em um servidor Debian sem X, então estou usando Xvfb e esta rodando perfeitamente.
Para rodar instalei o Xvfb e Chrome:
apt-get install xvfb google-chrome
Depois fiz o download do ChromeDriver aqui https://sites.google.com/a/chromium.org/chromedriver/downloads e movi para /usr/bin
para não te estresse.
Próximos passos da brincadeira:
(tools3) gabriel@localhost:~$ ps aux | grep chrome
gabriel 2523 0.0 0.0 13092 960 pts/9 S+ 14:35 0:00 grep chrome
gabriel 17964 0.0 0.5 109156 11504 pts/21 Sl 13:46 0:00 chromedriver --port=34911
gabriel 17970 0.0 0.0 0 0 pts/21 Z 13:46 0:02 [chrome] <defunct>
gabriel 18716 0.0 0.5 109156 11308 pts/21 Sl 13:47 0:00 chromedriver --port=41969
gabriel 18722 0.0 0.0 0 0 pts/21 Z 13:47 0:01 [chrome] <defunct>
gabriel 19654 0.0 0.5 109156 11028 pts/21 Sl 13:49 0:00 chromedriver --port=47171
gabriel 19660 0.0 0.0 0 0 pts/21 Z 13:49 0:01 [chrome] <defunct>
gabriel 20402 0.0 0.5 109156 11140 pts/21 Sl 13:50 0:00 chromedriver --port=38771
gabriel 20408 0.0 0.0 0 0 pts/21 Z 13:51 0:01 [chrome] <defunct>
gabriel 22411 0.0 0.5 110180 12132 pts/21 Sl 13:57 0:00 chromedriver --port=57737
gabriel 22417 0.1 0.0 0 0 pts/21 Z 13:57 0:02 [chrome] <defunct>
gabriel 25967 0.0 0.5 110180 11756 pts/9 Sl 14:07 0:00 chromedriver --port=59725
gabriel 25973 0.2 0.0 0 0 pts/9 Z 14:07 0:04 [chrome] <defunct>
gabriel 26733 0.0 0.5 109156 11540 pts/9 Sl 14:08 0:00 chromedriver --port=43321
gabriel 26739 0.1 0.0 0 0 pts/9 Z 14:08 0:02 [chrome] <defunct>
gabriel 28621 0.0 0.5 109156 11080 pts/9 Sl 14:11 0:00 chromedriver --port=46083
gabriel 28627 0.1 0.0 0 0 pts/9 Z 14:11 0:02 [chrome] <defunct>
gabriel 29381 0.0 0.5 110180 11748 pts/9 Sl 14:12 0:00 chromedriver --port=34833
gabriel 29387 0.3 0.0 0 0 pts/9 Z 14:12 0:04 [chrome] <defunct>
gabriel 31321 0.0 0.5 110212 11824 pts/9 Sl 14:19 0:00 chromedriver --port=39535
gabriel 31327 0.5 0.0 0 0 pts/9 Z 14:19 0:05 [chrome] <defunct>
[x] Matar o processo Chromedriver
def cleanup(self):
self.driver.quit()
if name == 'main': itau = ItauHome(Chrome()) try: itau.login('1234', '123456', 'MEUNOME', '000000', False) itau.go_to_ofx() print(itau.salvar_ofx(1, 1, 2018)) finally: itau.cleanup()
@henriquebastos dá pra reproduzir mesmo script mas pro BB?
To tendo problema com o webdriver e sem sucesso, não to sabendo muito bem como resolver... Fiz o download e salvei o chromedriver tanto no meu usr/bin quanto no folder do próprio .py.
Traceback (most recent call last):
File "itau.py", line 144, in <module>
itau = ItauHome(Chrome())
File "itau.py", line 24, in __init__
return super().__init__(chrome_options=options)
File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/chrome/webdriver.py", line 68, in __init__
self.service.start()
File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/common/service.py", line 83, in start
os.path.basename(self.path), self.start_error_message)
selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home
Consegui pegar o OFX finalmente! Alguma idéia de como fazer o parse do arquivo para um CSV, Dataframe, ou algo do tipo? Achei um OFXParser (https://github.com/jseutter/ofxparse), mas que não tá funcionando muito bem... alguém teve algum sucesso?
EDIT
Conseguir trabalhar com o OFX Parser (https://github.com/jseutter/ofxparse). Para quem se interessar, usei o módulo para converter em CSV e trabalhar com o arquivo em Excel.
import codecs
from ofxparse import OfxParser
import pandas as pd
with codecs.open('extrato.ofx', encoding="ISO-8859-1") as fileobj:
ofx = OfxParser.parse(fileobj)
account = ofx.account
statement = account.statement
all_transactions = []
for transaction in statement.transactions:
single_transaction = [
transaction.type,
transaction.date,
transaction.amount,
transaction.memo,
transaction.id
]
all_transactions.append(single_transaction)
df = pd.DataFrame(all_transactions)
df.columns = ['type', 'date', 'amount', 'memo', 'id']
df.to_csv('extrato.csv', sep=',', index=False)`
@luxu O BB já tem API aberta com uma documentação razoável: https://developers.bb.com.br/docs/#!/Checking_Account/get_statements_checking_account
Dei uma olhada nessa doc mas achei dificil implementar, axo q o uso é restrito ao navegador.
https://github.com/junqueira/bankscraper
docker-compose up
-> itau ta OK, santander tem um qrcode que da ruim :(
Olá,
Alguem ja implemento ou viu em algum lugar um scraper pra conta empresarial?
Lá se autentica com codigo de Operador e senha.
Obrigado
O Conta Azul faz.
Mas, infelizmente, não tem código disponível.
Em ter, 26 de fev de 2019 às 19:53, eduardoluizm notifications@github.com escreveu:
Olá,
Alguem ja implemento ou viu em algum lugar um scraper pra conta empresarial?
Lá se autentica com codigo de Operador e senha.
Obrigado
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/henriquebastos/itauscraper/issues/8#issuecomment-467648645, or mute the thread https://github.com/notifications/unsubscribe-auth/ACHdngvw6nJY-lcx8enFfffCq_j1nTOZks5vRbr0gaJpZM4VfUtd .
Pois é, eu vi que eles fazem e imagino que seja algo nesse sentido.
Pra pessoa fisica, ainda existe o site mobile e da pra fazer um scrapper, porem pra PJ eles arrancaram e exige o APP.. o app empresarial aceita codigo de operador.. talvez precise uma engenharia reversa pra descobrir como essas chamadas de API são executadas e simular um "app mobile".
Como ficou esse script com Selenium? Tá funcionando?
Fiz uma engenharia reversa no site para desktop e consegui fazer um script que acessa o extrato utilizando requests. Vou organizar ele, remover meus dados e depois posto no GitHub.
Fiz script para fazer as requisições pro Itaú sem usar o Selenium, se alguém quiser ver/testar: https://github.com/Lrcezimbra/itau/
Eu tava atrás de uma solução para digitar a senha do itau com o selenium, me ajudou muito, obrigado
O Itaú sacaneou a gente removendo o extrato do site mobile. Então eu implementei um primeiro rascunho de como seria obter o OFX.
Só testei no macOS com o ChromeDriver. Seria legal ter feedbacks de mais gente principalmente em outros sistemas operacionais.
O código tá "daquele jeito", mas funcionou de boa aqui. Próximo desafio é implementar o fluxo de obter os dados da fatura atual do cartão de crédito para só então pensar em como organizar essa zona.
Feedbacks são bem-vindos. :)