之前写过一篇“C# WebBrowser类使用总结”,前段时间因密码泄漏事件淘宝登录启用了验证码功能,导致之前所写的淘宝店铺助手使用的WebClient没有用武之地,当然还可以考虑弄个验证码自动识别或弹出给用户输入的做法,但没玩过这方面的编程还是无从下手。
没办法只好改用回WebBrowser控件,实际使用中碰到3个问题:
1. URL重复提交不被处理的问题。
2. session超时后需要重新登录,但上回登录成功的cookie还生效,实际上并没有登录操作就被判断为已经登录。
3. 页面弹出窗体自动无法自动确认导致后续页面无法执行的问题。
现在已经都解决了,现把各个解决的解决记录一下。
1. URL重复提交不处理的问题。
我们采用在调用Navigate前给URL增加一个每次调用都不一样的参数,就可以让控件以为是不同的URL所以会去处理。
if (url.IndexOf('?') == -1) { url += "?"; } else { url += "&"; } _savedTick = DateTime.Now.Ticks / 100000; // 10-ms url += "rtick=" + _savedTick.ToString(); _browser.Stop(); _browser.Navigate(url, target, bytePost, header);
另外发现有了个rtick参数后我们就可以的DocumentCompleted事件中判断URL里有没有这个参数,有才认为是对应URL的反回结果,所以上面把rtick值保存到类变量_savedTick中了,使用如下:
if (response != null && e.Url.ToString().Contains(string.Format("rtick={0}", _savedTick))) { _response = response; _status = BrowserStatus.Ingnore; _event.Set(); }
2. 重新登录时修改cookie
在网上找到使用wininet.dll的InternetSetCookie函数可以修改cookie:
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool InternetSetCookie(string lpszUrlName, string lbszCookieName, string lpszCookieData); // 登录时如果判断Document有效就把用于判断是否已登录的cookie关键字修改成一个固定字符串值 if (_browser.Document != null) { // set cookie InternetSetCookie(loginUrl, "_nk_", IGNORE_USER); }
然后在检查是否已经登录成功时忽略掉提交前修改成的用户名:
bool isLogin = false; Regex rx = new Regex("_nk_=(.*?);", RegexOptions.IgnoreCase); Match check = rx.Match(cookie); string username = null; if (check.Groups.Count == 2) { username = check.Groups[1].Value; } if (username == IGNORE_USER) { // 忽略用户 return isLogin; }
3. 禁用页面的javascript弹出窗体
引用名为Microsoft.mshtml的COM组件,描述名是Microsoft HTML Object Library,对应的tlb文件是mshtml.tlb。
然后using mshtml;
处理WebBrowser的Navigated事件:
using mshtml; _browser.Navigated += new WebBrowserNavigatedEventHandler(_browser_Navigated); private void _browser_Navigated(object sender, WebBrowserNavigatedEventArgs e) { IHTMLDocument2 vDocument = (IHTMLDocument2)_browser.Document.DomDocument; // 自动确认弹出窗体 vDocument.parentWindow.execScript("function alert(){return;}", "javascript"); vDocument.parentWindow.execScript("function confirm(){return;}", "javascript"); vDocument.parentWindow.execScript("function showModalDialog(){return;}", "javascript"); }
相关日志
Tags: C#/.NET