none
关于webbrowser的问题! RRS feed

  • 问题

  • 最近公司的一个子项目,需要自动登录到邮箱进行一些模拟操作,使用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>&nbsp;<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

    却始终无法获得需要的节点,这是为什么呢?请大牛指点下,不胜感激。

    2012年5月8日 6:41

全部回复

  • 如果你确定使用源代码查看可以看到,那么:

    e.GetElementsByTagName("a").Cast<HtmlElement>().Where(e=>e.GetAttribute("title")=="用于清除邮件的工具").FirstOrDefault();

    2012年5月8日 7:06
  • 谢谢云游心踪的答复,测试程序界面如下:


    在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不是当前显示页面代码?

    我是手工右键查看源代码里看到的我需要的节点源代码的。


    2012年5月8日 7:36
  • 又仔细看了下日志,发现

    webbrowser1.Document并不是当前显示页面的代码,而是跳转之前(上一个页面)的代码,这是怎么回事呢?请各位大牛指点迷津?

    2012年5月8日 8:24
  • 又仔细看了下日志,发现

    webbrowser1.Document并不是当前显示页面的代码,而是跳转之前(上一个页面)的代码,这是怎么回事呢?请各位大牛指点迷津?

    跳转到收件箱,请使用webbrowser.Navigate再次跳转下,然后在DocumentComplete中处理寻找看看。
    2012年5月8日 8:31
  •  

    我跳转到收件箱是使用如下代码:

    lnkInbox = webBrowser1.Document.GetElementById("h_inboxCount");
                   if (lnkInbox != null)
                   {
                        lnkInbox.InvokeMember("click");
                        return;
                  }

    您是说使用webbrowser.Navigate跳转?但是我不知道收件箱的绝对地址,如何跳转呢?谢谢!

    2012年5月8日 8:55
  • 你先在IE中登录,成功之后把地址栏的地址拷贝下来。

    然后WinForm “转到收件箱”按钮:

    webbrowser.Navigate(……); //在“转到收件箱”你上面一段代码之前请先Navigate到你拷贝的那个字符串url一遍,然后再做看看。

    lnkInbox = webBrowser1.Document.GetElementById("h_inboxCount");
                   if (lnkInbox != null)
                   {
                        lnkInbox.InvokeMember("click");
                        return;
                  }

    操作时候,先登录,然后再点击“转到收件箱”即可。


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年5月8日 9:00
    版主
  • to志愿者:谢谢您的答复。

    to 云游:我想当然了。获取节点的href属性就可获得需跳转的地址,那是不是说以后每个页面都需要Navigate一下,有些节点并没有href属性该怎么办呢?

    十分感谢各位的答复!

    2012年5月8日 9:29
  • 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");               
                          
                        }
                    }
                }
            }
    
          
        }


    给我写信: QQ我:点击这里给我发消息


    2012年5月8日 14:03
  • 谢谢桦仔的细心答复,非常感谢。

    我的项目需求和你的非常类似,只是步骤更多一些,大概需要5、6次跳转和提交才可以,我也是在webBrowser1_DocumentCompleted事件中处理。

    现在碰到另一个问题,多次跳转步骤都是在webBrowser1_DocumentCompleted处理,依靠标志位进行区分进行到哪一步。

    测试过程中发现每个步骤webBrowser1_DocumentCompleted都会被多次触发。

    在“管理规则”跳转时,由于脚本未被完全加载,头几次DocumentCompleted事件处理会发生错误,这如何解决呢?

    感谢每一位帮助答复我得大牛们,菜鸟学到了很多。谢谢!

    2012年5月8日 16:10
  • 或者你可以在DocumentCompleted事件处理函数那里获取URL,根据URL来进行下一步的动作

      void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
            {
                MessageBox.Show(this.webBrowser1.Url.ToString());


    给我写信: QQ我:点击这里给我发消息

    2012年5月8日 17:10
  • 王:)

    是的,每一次DocumentCompleted都会被执行(当你设置Uri或者是Navigate方法时候)。不过请记住,由于每一个页面元素不同,因此可以据此进行判断(假设“登录”有登录按钮,收件箱有收件箱按钮……)。那么你就可以用if对这些元素进行判断,继而确定究竟是哪个页面。


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年5月9日 0:59
    版主
  • 刚才看了一下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加油


    给我写信: QQ我:点击这里给我发消息


    2012年5月9日 2:02
  • 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
    2012年5月9日 4:08
  • 补充,要不这样:

    你设置一个类的变量flag(布尔类型,一开始是false),然后在成功登录的Navigate之后设置为true。注意在DocumentComplete中判断是true还是false,处理对应的东西看看……


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年5月9日 5:29
    版主
  • 补充,要不这样:

    你设置一个类的变量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
    2012年5月9日 6:46
  • 联接当前页面。
    
    -------------------
    通常有如下用法:
    <a href="#" onclick="window.close()">关闭</a>
    将href="#"是指联接到当前页面,其实是无意义的,页面也不会刷新,关键是后面的onclick,当点击“关闭”时,会执行window.close()代码。
    
    你或许会说为什么不直接写成<a onclick="window.close()">关闭</a>
    如果这样写,关闭这两个字就不会作为超联接处理,效果看上去会差一些。你可以自己试试。

    给我写信: QQ我:点击这里给我发消息

    2012年5月9日 8:50
  • 您好

    昨晚做了一晚,你看行不

    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元素

    由于我的代码不工整 或者 网速不一样有可能需要加上延时之类的 所以请你见谅

    附上截图


    给我写信: QQ我:点击这里给我发消息

    2012年5月9日 8:58

  • 给我写信: QQ我:点击这里给我发消息

    2012年5月9日 9:02
  • 哇哦,非常感谢桦兄,今晚逐行学习下先。有问题再请教。

    万分感谢中。。。。

    2012年5月9日 9:35
  • 不用谢,我也是菜鸟,互相学习


    给我写信: QQ我:点击这里给我发消息

    2012年5月9日 9:43
  • 谢谢桦兄。刚才我仔细看了下你的代码,在处理
    <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获取的网页源码流与你在浏览器中所看到的页面视图也是不同的,”

    我想说明的也是这个问题,还在研究中。

    再次谢谢桦兄的指点。
    2012年5月9日 11:51
  • 那篇文章我看了http://www.cnblogs.com/finallyliuyu/archive/2010/10/28/1863691.html

    代码差不多

    针对“webbrowser.url已经显示当前页面是“管理规则”的地址,可是
    webbrowser.Document中,还是上一个界面(收件箱)的网页源代码。”

    实际上网页使用了div,所以url没有跳转,关于div, 你可以查一下网页设计的资料,一般学过网页设计的都知道iframe div这些html元素


    给我写信: QQ我:点击这里给我发消息


    2012年5月9日 15:00
  • 确实太菜,没明白您说的,我先补下html知识。

    那我该如何处理才能跳转到我需要的页面呢?

    2012年5月10日 0:25
  • 找到那个超链接的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;
                    }
                }


    给我写信: QQ我:点击这里给我发消息


    2012年5月10日 1:09
  • 谢谢桦兄。昨天临时出差,耽误了一天时间。

    我按照您的提示,试了下,在收件箱页面,“管理规则”的ID是“ManageRules”,使用您给出的herfclick函数正常跳转。

    但是在“管理规则”页面,“新建”按钮的ID是“NewFilter”,网页代码如下:

    <div class="UiButtonPadding"> 
    
                <input id="NewFilter" type="button" name="NewFilter"  class="UiButton" value="&#26032;&#24314;" onclick="$BSI.navigateTo('EditRule.aspx?n=1755372272');" >
    
                <input id="DeleteFilter" type="submit" name="DeleteFilter" class="UiButton" disabled="true" value="&#21024;&#38500;">
    
            </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
    2012年5月11日 2:20
  • 我也试过,不行,无能为力了,不好意思

    给我写信: QQ我:点击这里给我发消息

    2012年5月11日 4:45
  • 已经麻烦这么多天了,谢谢!
    2012年5月11日 5:54
  • 已经麻烦这么多天了,谢谢!
    msdnmg@microsoft.com 发过去问问
    2012年5月11日 6:12
  • 谢谢云游,我发了份邮件过去,不知道会不会答复!等待中。。。。

    突然想起来,是用中文发的,不知道会不会被鄙视。

    • 已编辑 王炜 2012年5月11日 7:59
    2012年5月11日 7:14