询问者
关于webbrowser的问题!

问题
-
最近公司的一个子项目,需要自动登录到邮箱进行一些模拟操作,使用vs2008 winform内嵌webbrowser,已经实现自动登录和链接跳转,但是在获取邮箱内菜单中的按钮节点时,出现问题。如下图,需要模拟点击菜单中“计划清理”按钮。
在页面代码中已搜到对应代码:
<a href="#" class="c_ml" title="用于清除邮件的工具" onclick="try{if (this.className.indexOf('DisabledLink') == -1) {$menu.create(event,0)}}catch(e){};return false;"><span class="c_ddtxt">整理</span> <span class="c_chev">▼</span></a><ul style="visibility: hidden; display: block; left: 165px; top: 29px;" class="c_m t_hovl" onclick="$menu.closeCurrent();"><li style="display: block;" aid="moveAllFromSender"><a id="MoveAllFromSender" href="#"><span>移动来自以下发件人的所有邮件...</span></a></li><li style="display: block;" aid="deleteAllFromSender"><a id="DeleteAllFromSender" href="#"><span>删除来自以下发件人的所有邮件...</span></a></li><li style="display: none;" aid="unsubscribe"><a id="Unsubscribe" href="#"><span>取消订阅</span></a></li><li style="display: block;" aid="scheduleCleanup"><a id="ScheduleCleanup" href="#"><span>计划清理</span></a></li><li aid="blockAllFromSender" style="display: none;"><a id="BlockAllFromSender" href="#"><span>阻止...</span></a></li><li style="display: block;" aid="markAllRead"><a id="MarkAllRead" href="#">将此文件夹标记为已读</a></li><li style="display: block;" aid="deleteAll"><a id="DeleteAll" href="#">清空此文件夹</a></li><div class="c_sep"></div><li aid="manageRules"><a class="LinkColor" id="ManageRules" href="#"><span>管理规则</span></a></li></ul><div class="c_shad" style="position: absolute; top: 32px; left: 168px; display: none; background-color: rgb(0, 0, 0); opacity: 0.2; visibility: hidden; width: 206px; height: 175px;"></div></li><li class="ToolbarItem c_mcp " id="MarkAs">
但是利用程序各种方法
webBrowser1.Document.GetElementById
webBrowser1.Document.ALL
webBrowser1.Document.GetElementsByTagName却始终无法获得需要的节点,这是为什么呢?请大牛指点下,不胜感激。
全部回复
-
谢谢云游心踪的答复,测试程序界面如下:
在webbrowser已经载入邮箱收件箱界面后,点击“计划清理”按钮,按钮响应事件内记录日志:
lnkInboxs = webBrowser1.Document.GetElementsByTagName("a");
if (lnkInboxs != null)
{
foreach (HtmlElement elem in lnkInboxs)
{
PrintLog("href:=" + elem.GetAttribute("href") + " title id:=" + elem.GetAttribute("title"));
}
}但是无法发现“用于清理邮件的工具”链接,难道webBrowser1.Document不是当前显示页面代码?
我是手工右键查看源代码里看到的我需要的节点源代码的。
-
你先在IE中登录,成功之后把地址栏的地址拷贝下来。
然后WinForm “转到收件箱”按钮:
webbrowser.Navigate(……); //在“转到收件箱”你上面一段代码之前请先Navigate到你拷贝的那个字符串url一遍,然后再做看看。
lnkInbox = webBrowser1.Document.GetElementById("h_inboxCount");
if (lnkInbox != null)
{
lnkInbox.InvokeMember("click");
return;
}操作时候,先登录,然后再点击“转到收件箱”即可。
-
to "那是不是说以后每个页面都需要Navigate一下" ,不需要的只需要在webBrowser1_DocumentCompleted事件处理函数里判断就可以了
我之前做了一个自动签到程序,一开始只需要登录一下签到网站的登录页面就可以了,登录成功之后你需要查看网页的html代码
比如你想点击“计划清理”按钮, 你就需要知道那个按钮是使用什么html标签,如果是在表单里的就调用
InvokeMember("submit")或者InvokeMember("click")附上代码,在编程志愿者大哥帮助下完成的:
public partial class Form1 : Form { /// <summary> /// 获取SignButton /// </summary> private HtmlElement SignButton { get; set; } private bool IsSigned { get; set; } public Form1() { InitializeComponent(); IsSigned = false; //默认没有签到 } private void button1_Click(object sender, EventArgs e) { if (!NetworkUtil.IsConnectedInternet()) { MessageBox.Show("本机已脱网!"); return; } this.webBrowser1.Navigate(new Uri(@"http://www.kuaipan.cn/index.php?ac=account&op=login")); //打开链接 this.webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted); } /// <summary> /// 完成html页面加载 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { if (!IsSigned) { WebBrowser wb = (WebBrowser)sender; if (wb.ReadyState == WebBrowserReadyState.Complete) { SignButton = wb.Document.GetElementById("usersignlink"); if (SignButton == null) { System.Windows.Forms.HtmlDocument document = wb.Document; if (document == null) { //MessageBox.Show(this.webBrowser1.Url.ToString()); return; } HtmlElementCollection hec = document.All; foreach (HtmlElement he in hec) //轮循 { string id = he.Id; if ((id == "userName") || (id == "userPwd") || (id == "submit")) //减少处理 { switch (id) { case "userName": he.SetAttribute("value", "xxx"); break; case "userPwd": he.SetAttribute("value", "xxx"); break; //赋密码 default: break; } } } wb.Document.Forms["loginform"].InvokeMember("submit"); } else { //否则进入签到页面 IsSigned = true; SignButton.InvokeMember("Click"); } } } } }
- 已编辑 Steven.桦仔 2012年5月8日 14:04
-
谢谢桦仔的细心答复,非常感谢。
我的项目需求和你的非常类似,只是步骤更多一些,大概需要5、6次跳转和提交才可以,我也是在webBrowser1_DocumentCompleted事件中处理。
现在碰到另一个问题,多次跳转步骤都是在webBrowser1_DocumentCompleted处理,依靠标志位进行区分进行到哪一步。
测试过程中发现每个步骤webBrowser1_DocumentCompleted都会被多次触发。
在“管理规则”跳转时,由于脚本未被完全加载,头几次DocumentCompleted事件处理会发生错误,这如何解决呢?
感谢每一位帮助答复我得大牛们,菜鸟学到了很多。谢谢!
-
刚才看了一下Hotmail的登录页面,html代码比金山快盘还要复杂,而且我找不到 input标签 ,下面是金山快盘的部分html代码
<!--登录 S--> <div class="account-wrapper"> <div class="account-mod" > <form method="post" id="loginform" action="https://www.kuaipan.cn/index.php?ac=account&op=login"> <div id="erroInfo" class="erro-info" style="visibility:hidden;"></div> <div class="account-frm clearfix"> <label for="username" class="f14">注册邮箱:</label> <input type="text" autocomplete="off" name="username" id="userName" maxlength="32" value="xxx@163.com" tabindex="1" class="account-txt" /> <input type="checkbox" name="rememberme" id="rememberme" value="1" checked class="account-chk" /> <span>记住我</span> </div> <div class="account-frm clearfix"> <label for="userpwd" class="f14">密码:</label> <input type="password" autocomplete="off" name="userpwd" id="userPwd" maxlength="32" tabindex="2" class="account-txt" /> <a title="从这里找回密码" href="http://www.kuaipan.cn/account_reset.htm?email=xxx@163.com">忘记密码?</a> </div> <div class="account-frm clearfix"> <input type="submit" tabindex="3" value="" class="btn-login ti" /> <a href="javascript:;" id="qqlogin" class="pt10" title="使用QQ登录快盘" ><b class="ico ico-qq"></b>使用QQ账号登录</a> </div>
而且我找不到hotmail的form表单,input标签
希望LZ加油
- 已编辑 Steven.桦仔 2012年5月9日 2:03
-
to 志愿者:您是说通过判断每个页面独有的节点元素来判断当前步骤,这个想法非常好,我确实没有想到过,在此谢过。只是好像这样还是无法判断当前页面已完全加载。
to 桦兄:hotmail登陆我倒是已经实现,只要获取
btnSubmit = webBrowser1.Document.All["idSIButton9"];
tbUserid = webBrowser1.Document.All["i0116"];
tbPasswd = webBrowser1.Document.All["i0118"];再SetAttribute和InvokeMember就可以实现登陆了。
总结一下之前碰到的问题和解决办法,再说一下碰到的新问题。
当时程序已实现自动登陆和跳转到收件箱,但是无法获取到收件箱页面的“管理规则”等按钮节点。后来经过各位指点,发现虽然webbrowser已经显示收件箱页面,但是其实webbrowser.document的内容还是上一个页面的,需要在程序中调用webbrowser.Navigate,将当前webbrowser.url转为收件箱页面就可以顺利找到“管理规则”按钮。至此问题解决。
碰到新问题:程序通过Navigate跳转到“管理规则”页面后,确认当前webbrowser.url已经是“管理规则”页面地址,但是仍然无法获取页面内任何链接节点。页面如下图:
我在DocumentCompleted事件内,确认webbrowser.url已经是当前页面url,获取页面所有链接却都为空,彻底迷惑了。
啰啰嗦嗦这么多,再次感谢志愿者和桦兄的答复。
- 已编辑 王炜 2012年5月9日 4:09
-
补充,要不这样:
你设置一个类的变量flag(布尔类型,一开始是false),然后在成功登录的Navigate之后设置为true。注意在DocumentComplete中判断是true还是false,处理对应的东西看看……
to 志愿者:
呵呵,我现在就是这么做的。谢谢你啊!
我觉得是是在处理这句代码时出现的问题:
<a class="LinkColor" id="ManageRules" href="#"><span>管理规则</span>
我用了两种方法:
方法一:webbrowser.Document.GetElementById("ManageRules");然后调用InvokeMember("click"),但是发现webbrowser虽然显示已跳转,但是webbrowser.Document还是保留的上一个页面(收件箱页面)的内容。
方法二:直接处理url。观察管理规则的url后,
url = webBrowser1.Url.ToString().Replace("InboxLight.aspx", "ManageRules.aspx");
webBrowser1.Navigate(url);
结果发现虽然显示页面也跳转了,url也是管理规则页面的url,但是webbrowser.Document里的内容却很奇怪,乱七八糟的东西。
所以我感觉还是处理
<a class="LinkColor" id="ManageRules" href="#"><span>管理规则</span>
的问题,这里的“#”代表什么?请各位指点下哈!谢谢!
- 已编辑 王炜 2012年5月9日 7:29
-
您好
昨晚做了一晚,你看行不
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Windows.Forms; namespace SignInProgram { public partial class Formhotmail : Form { /// <summary> /// 是否点击了计划清理按钮 /// </summary> private bool ScheduleCleanup = false; public Formhotmail() { InitializeComponent(); } /// <summary> /// 登录 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnLogin_Click(object sender, EventArgs e) { if (!NetworkUtil.IsConnectedInternet()) { MessageBox.Show("本机已脱网!"); return; } this.webBrowser1.Navigate(new Uri(@"http://www.hotmail.com")); //打开hotmail登录页面 this.webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted); } /// <summary> /// DocumentCompleted事件处理函数 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { WebBrowser wb = (WebBrowser)sender; if (wb.ReadyState == WebBrowserReadyState.Complete) { if (wb.Document.GetElementById("c_profile")!=null) //判断页面中有没有个人资料这个超链接,如果有表示已经登录 { herfclick("h_inboxCount"); //跳转到收件箱 } else { Login(wb); } if(this.ScheduleCleanup==true) { herfclick("ScheduleCleanup"); //跳转到计划清理 this.ScheduleCleanup = false; } } //wb.Refresh(); } /// <summary> /// 计划清理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSchClear_Click(object sender, EventArgs e) { this.ScheduleCleanup = true; this.webBrowser1.Refresh(); } /// <summary> /// 登录 /// </summary> /// <param name="wb"></param> void Login(WebBrowser wb) { System.Windows.Forms.HtmlDocument document = wb.Document; if (document == null) { //MessageBox.Show(this.webBrowser1.Url.ToString()); return; } HtmlElementCollection hec = document.All; foreach (HtmlElement he in hec) //轮循 { string id = he.Id; if ((id == "i0116") || (id == "i0118") || (id == "idSIButton9")) //减少处理 { switch (id) { case "i0116": he.SetAttribute("value", "XXX@hotmail.com"); break; //赋邮箱 case "i0118": he.SetAttribute("value", "XXX"); break; //赋密码 case "idSIButton9": he.InvokeMember("click"); break; default: break; } } } wb.Document.Forms["f1"].InvokeMember("submit"); } /// <summary> /// 模拟点击超链接 /// </summary> /// <param name="url"></param> private void herfclick(string id) { for (int i = 0; i < this.webBrowser1.Document.All.Count; i++) { if (this.webBrowser1.Document.All[i].TagName == "A" && this.webBrowser1.Document.All[i].GetAttribute("id").ToString().Trim() == id) { this.webBrowser1.Document.All[i].InvokeMember("click");//引发”CLICK”事件 break; } } } } }
给一个网址给你
http://blog.sina.com.cn/s/blog_8dfc16030100xj1v.html
建议使用谷歌浏览器,按F12 键查看HTML元素
由于我的代码不工整 或者 网速不一样有可能需要加上延时之类的 所以请你见谅
附上截图
-
谢谢桦兄。刚才我仔细看了下你的代码,在处理
<a class="LinkColor" id="ManageRules" href="#"><span>管理规则</span>
代码时,你使用的InvokeMember("click")。虽然显示界面已经跳转到“管理规则”页面,但奇怪的是,
webbrowser.url已经显示当前页面是“管理规则”的地址,可是
webbrowser.Document中,还是上一个界面(收件箱)的网页源代码。
我下午搜了一篇文章,http://www.cnblogs.com/finallyliuyu/archive/2010/10/28/1863691.html
里面有句话:
“另外 如果url中还有“#”字段的,用httpresponse,httprequest获取的网页源码流与你在浏览器中所看到的页面视图也是不同的,”
我想说明的也是这个问题,还在研究中。
再次谢谢桦兄的指点。 -
- 已编辑 Steven.桦仔 2012年5月9日 15:00
-
找到那个超链接的ID 或者按钮的ID
然后传入ID ,利用谷歌浏览器的帮助去找ID ,F12
/// <summary> /// 模拟点击超链接 /// </summary> /// <param name="url"></param> private void herfclick(string id) { for (int i = 0; i < this.webBrowser1.Document.All.Count; i++) { if (this.webBrowser1.Document.All[i].TagName == "A" && this.webBrowser1.Document.All[i].GetAttribute("id").ToString().Trim() == id) { this.webBrowser1.Document.All[i].InvokeMember("click");//引发”CLICK”事件 break; } }
- 已编辑 Steven.桦仔 2012年5月10日 1:09
-
谢谢桦兄。昨天临时出差,耽误了一天时间。
我按照您的提示,试了下,在收件箱页面,“管理规则”的ID是“ManageRules”,使用您给出的herfclick函数正常跳转。
但是在“管理规则”页面,“新建”按钮的ID是“NewFilter”,网页代码如下:
<div class="UiButtonPadding"> <input id="NewFilter" type="button" name="NewFilter" class="UiButton" value="新建" onclick="$BSI.navigateTo('EditRule.aspx?n=1755372272');" > <input id="DeleteFilter" type="submit" name="DeleteFilter" class="UiButton" disabled="true" value="删除"> </div> <p />
因此使用如下代码:
for (int i = 0; i < this.webBrowser1.Document.All.Count; i++) { if (this.webBrowser1.Document.All[i].TagName == "INPUT" && this.webBrowser1.Document.All[i].GetAttribute("id").ToString().Trim() == "NewFilter") { this.webBrowser1.Document.All[i].InvokeMember("click");
break; } }
仍然无法找到“NewFilter”按钮。
不好意思,反复骚扰,十分感激。
- 已编辑 王炜 2012年5月11日 2:35