背景
ETrade身份验证系统让我创建一个RequestToken,然后执行授权URL,打开一个ETrade页面。
用户登录以授权其帐户上的活动。
他们收到一个pin,他们在我的应用程序中输入。
我使用RequestToken和Pin调用ExchangeRequestTokenForAccessToken。
然后我们就开始跑了。
问题
问题是我正在创建一个在后台持续运行的服务。没有任何用户登录。相反,我不会做任何交易。只需处理数字,寻找符合特定标准的股票。
我无法想象如何让这个无人看管。
谢谢,布拉德。
答案 0 :(得分:1)
以前,我使用了一系列WebRequests并手动添加了标头来模拟授权页面。直到大约一年前,当ETrade使用看似跟踪信息的东西复杂化它们的标题时,这种情况一直有效。我现在使用http://watin.org/登录,并删除验证码。
Sloppy代码如下所示:
libjsig.so
答案 1 :(得分:1)
Brad Melton的当前版本代码。 WatiN已更改,不再包含IE.AttachToIE功能。 因此,IEStaticInstanceHelper现在称为StaticBrowserInstanceHelper,但该代码很难找到,所以我在此处将其包含在内。
class StaticBrowserInstanceHelper<T> where T : Browser {
private Browser _browser;
private int _browserThread;
private string _browserHwnd;
public Browser Browser {
get {
int currentThreadId = GetCurrentThreadId();
if (currentThreadId != _browserThread) {
_browser = Browser.AttachTo<T>(Find.By("hwnd", _browserHwnd));
_browserThread = currentThreadId;
}
return _browser;
}
set {
_browser = value;
_browserHwnd = _browser.hWnd.ToString();
_browserThread = GetCurrentThreadId();
}
}
private int GetCurrentThreadId() {
return Thread.CurrentThread.GetHashCode();
}
}
ETrade的登录页面也已更改。他们有几个。我一直检查的所有登录页面都有一个USER字段和一个PASSWORD字段,但是登录按钮有各种看起来很脆弱的名字。因此,如果这不起作用,那就是我要检查的第一件事。 其次,如果我直接进入auth页面,它会提示登录,但它经常不会带你到auth页面。 通过访问主页登录,然后转到身份验证页面,我获得了更一致的结果。
static public string GetPin(string username, string password, string logonLink, string authLink) {
// Settings.Instance.MakeNewIeInstanceVisible = false;
var StaticInstanceHelper = new StaticBrowserInstanceHelper<IE>();
Settings.AutoStartDialogWatcher = false;
// This code doesn't always handle it well when IE is already running, but it won't be in my case. You may need to attach to existing, depending on your context.
using (StaticInstanceHelper.Browser = new IE(logonLink)) {
string authCode = "";
// Browser reference was failing because IE hadn't started up yet.
// I'm in the background, so I don't care how long it takes.
// You may want to do a WaitFor to make it snappier.
Thread.Sleep(5000);
if (StaticInstanceHelper.Browser.ContainsText("Scheduled System Maintenance")) {
throw new ApplicationException("eTrade down for maintenance.");
}
TextField user = StaticInstanceHelper.Browser.TextField(Find.ByName("USER"));
TextField pass2 = StaticInstanceHelper.Browser.TextField(Find.ByName("PASSWORD"));
// Class names of the Logon and Logoff buttons vary by page, so I find by text. Seems likely to be more stable.
Button btnLogOn = StaticInstanceHelper.Browser.Button(Find.ByText("Log On"));
Element btnLogOff = StaticInstanceHelper.Browser.Element(Find.ByText("Log Off"));
Button btnAccept = StaticInstanceHelper.Browser.Button(Find.ByValue("Accept"));
TextField authCodeBox = StaticInstanceHelper.Browser.TextField(Find.First());
if (user != null && btnLogOn != null &&
user.Exists && pass2.Exists && btnLogOn.Exists) {
user.Value = username;
pass2.Value = password;
btnLogOn.Click();
}
Thread.Sleep(1000);
if (StaticInstanceHelper.Browser.ContainsText("Scheduled System Maintenance")) {
Element btnContinue = StaticInstanceHelper.Browser.Element(Find.ByName("continueButton"));
if (btnContinue.Exists)
btnContinue.Click();
}
btnLogOff.WaitUntilExists(30);
// Here we go, finally.
StaticInstanceHelper.Browser.GoTo(authLink);
btnAccept.WaitUntilExists(30);
btnAccept.Click();
authCodeBox.WaitUntilExists(30);
authCode = authCodeBox.Value;
StaticInstanceHelper.Browser.Close();
return authCode;
}
}
能够像这样自动化它意味着我不再关心令牌的有效期。谢谢BradM!