C# WebBrowser控件使用技巧补充

之前写过一篇“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:

Leave a Reply


提醒: 评论者允许使用'@user空格'的方式将自己的评论通知另外评论者。例如, ABC是本文的评论者之一,则使用'@ABC '(不包括单引号)将会自动将您的评论发送给ABC。请务必注意user必须和评论者名相匹配(大小写一致)。