User Login via Selenium
PaulNobrega opened this issue · comments
PaulNobrega commented
Good library. I would suggest a modification to your ETradeOAuth class to support automated login. Below is a working test script to benefit others if you decided to not add the feature.
from rauth import OAuth1Service
import undetected_chromedriver.v2 as uc
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
import time
import xmltodict
import json
class AutomatedLogin():
def __init__(self, consumer_key, consumer_secret, web_username, web_password):
self.consumer_key = consumer_key
self.consumer_secret = consumer_secret
self.web_username = web_username
self.web_password = web_password
self.service = OAuth1Service(
name='etrade',
consumer_key=consumer_key,
consumer_secret=consumer_secret,
request_token_url='https://apisb.etrade.com/oauth/request_token',
access_token_url='https://apisb.etrade.com/oauth/access_token',
authorize_url='https://us.etrade.com/e/t/etws/authorize?key={}&token={}',
base_url='https://apisb.etrade.com')
self.oauth_token, self.oauth_token_secret = self.service.get_request_token(params={'oauth_callback': 'oob', 'format': 'json'})
self.auth_url = self.service.authorize_url.format(consumer_key, self.oauth_token)
self.verifier = self.__get_verifier(headless=True, action_delay_sec=2)
if self.verifier:
self.session = self.service.get_auth_session(self.oauth_token, self.oauth_token_secret, params={'oauth_verifier': self.verifier})
def __get_verifier(self, headless=True, action_delay_sec=2):
if headless:
options = uc.ChromeOptions()
options.headless = True
options.add_argument('--headless')
driver = uc.Chrome(options=options)
print(f'Headless web login with action_delay set to: {action_delay_sec} seconds')
else:
driver = uc.Chrome()
web_action = ActionChains(driver)
try:
with driver:
driver.get(self.auth_url)
# log in
username = driver.find_element_by_name("USER")
password = driver.find_element_by_name("PASSWORD")
username.send_keys(web_username)
password.send_keys(web_password)
driver.find_element_by_id("logon_button").click()
time.sleep(action_delay_sec)
web_action.send_keys(Keys.TAB).send_keys(Keys.RETURN).perform()
return driver.find_element_by_tag_name("input").get_attribute("value")
except Exception as e:
print(str(e))
return
# User Parameters
consumer_key = 'dxxx...xxx007'
consumer_secret = 'e7xxx...xxxa4e8'
web_username = 'user_name'
web_password = 'password'
# Automated Login
login = AutomatedLogin(consumer_key, consumer_secret, web_username, web_password)
# Test Session
url = 'https://apisb.etrade.com/v1/accounts/list'
resp = login.session.get(url, params={'format': 'json'})
resp_json = json.dumps(xmltodict.parse(resp.text))
print(resp_json)
1rocketdude commented
we discussed this idea a couple of years back and decided that having automated logins was a security risk with large negative ramifications. That said, I consider having the ability to use autologin a useful tool in someone's toolbox. Having the web_username and web_password in plaintext anywhere is asking for trouble, especially as much of this codebase ends up in revision control system somewhere.
Potentially, is this an external library that could be packaged into a module which depends on pyetrade? Then, a user would have to go to the extra work, and acknowledge the security risks without burdening the pyetrade modules?
thanks for providing the code - in the mean time, users could use this approach themselves.
… On Mar 14, 2021, at 9:38 AM, PaulNobrega ***@***.***> wrote:
Good library. I would suggest a modification to your ETradeOAuth class to support automated login. Below is a working test script to benefit others if you decided to not add the feature.
from rauth import OAuth1Service
import undetected_chromedriver.v2 as uc
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
import time
import xmltodict
import json
class AutomatedLogin():
def __init__(self, consumer_key, consumer_secret, web_username, web_password):
self.consumer_key = consumer_key
self.consumer_secret = consumer_secret
self.web_username = web_username
self.web_password = web_password
self.service = OAuth1Service(
name='etrade',
consumer_key=consumer_key,
consumer_secret=consumer_secret,
request_token_url='https://apisb.etrade.com/oauth/request_token',
access_token_url='https://apisb.etrade.com/oauth/access_token',
authorize_url='https://us.etrade.com/e/t/etws/authorize?key={}&token={}',
base_url='https://apisb.etrade.com')
self.oauth_token, self.oauth_token_secret = self.service.get_request_token(params={'oauth_callback': 'oob', 'format': 'json'})
self.auth_url = self.service.authorize_url.format(consumer_key, self.oauth_token)
self.verifier = self.__get_verifier(headless=True, action_delay_sec=2)
if self.verifier:
self.session = self.service.get_auth_session(self.oauth_token, self.oauth_token_secret, params={'oauth_verifier': self.verifier})
def __get_verifier(self, headless=True, action_delay_sec=2):
if headless:
options = uc.ChromeOptions()
options.headless = True
options.add_argument('--headless')
driver = uc.Chrome(options=options)
print(f'Headless web login with action_delay set to: {action_delay_sec} seconds')
else:
driver = uc.Chrome()
web_action = ActionChains(driver)
try:
with driver:
driver.get(self.auth_url)
# log in
username = driver.find_element_by_name("USER")
password = driver.find_element_by_name("PASSWORD")
username.send_keys(web_username)
password.send_keys(web_password)
driver.find_element_by_id("logon_button").click()
time.sleep(action_delay_sec)
web_action.send_keys(Keys.TAB).send_keys(Keys.RETURN).perform()
return driver.find_element_by_tag_name("input").get_attribute("value")
except Exception as e:
print(str(e))
return
# User Parameters
consumer_key = 'dxxx...xxx007'
consumer_secret = 'e7xxx...xxxa4e8'
web_username = 'user_name'
web_password = 'password'
# Automated Login
login = AutomatedLogin(consumer_key, consumer_secret, web_username, web_password)
# Test Session
url = 'https://apisb.etrade.com/v1/accounts/list'
resp = login.session.get(url, params={'format': 'json'})
resp_json = json.dumps(xmltodict.parse(resp.text))
print(resp_json)
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub <#46>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ABE3CHFI6BR4ZUIVEDI2PWDTDTJ7JANCNFSM4ZFCY2WA>.
Jesse Cooper commented
Thanks for the example. As @1rocketdude said this has been talked about in the past and is something the application leveraging pyetrade should implement. There has been a suggestion to create a discussion board around pyetrade for topics like this. I am going to look into this and any suggestions around this are appreciated.