怎样获得InvokeMember("click")操作完成的通知?

kelsius 2016-03-17 05:42:43
我想做一个自动签到的程序。
在Form1里放了一个WebBrowser控件来显示网页,加载网页完成后会进入webBrowser1_DocumentCompleted函数体,函数体内模拟单击网页上的“签到”按钮,由于验证码与URI并不对应,所以我想直接截图。现在问题是,没等签到框弹出,就已经提前截了图。
刚刚接触C#,对窗体应用程序机制不了解,搜了很多资料未果,希望得到大家的指点。感激不尽!

附上部分关键代码:

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//网页加载完成,寻找签到html元素,并模拟单击事件
HtmlDocument doc = webBrowser1.Document; //获得webBrowser1当前显示的网页,即html文档
if (doc == null)
return ;
HtmlElement elem_signIn = doc.GetElementById("header-sin"); //找到“签到”的html元素
if (elem_signIn == null)
return ;
elem_signIn.FirstChild.InvokeMember("click"); //模拟单击“签到”按钮

//对弹出的”签到框“中的验证码截图,并保存
Bitmap captcha = new Bitmap(60, 20);
/* 截图操作省略 */
captcha.Save("C:\\Users\\Desktop\\1.jpg");
}


问题:截到的图片不是验证码,而是它底下一层的图片。看起来“截图操作”发生于“签到框弹出”之前。请问有什么办法呢?谢谢大家!
...全文
289 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
kelsius 2016-04-22
  • 打赏
  • 举报
回复
恩,很抱歉这么久了才来结贴。 最终我使用委托技术来解决。创建定时器是可以的,但是定时器是和主线程分开的,因此当定时器中断转到中断服务程序,我们要在这里截图,因此需要引用webBrowser1这个Form1类的私有变量,很明显,这里是不能够引用的。那怎么能够在定时器线程中去执行这个任务呢?委托技术就是我们“委托”主线程,让它来帮我们做。实际上任务的真正执行还是由主线程来完成的。说了这么多,上代码结合理解看一下吧:
            
            if (this.webBrowser1.InvokeRequired)  //Timer thread calling
            {
                snapshot_delegate sd = new snapshot_delegate(Snapshot);
                Invoke(sd);
            }
            else  //委托主线程来帮忙执行
            {
                Bitmap b = new Bitmap(60, 20);
                Point p_webBrowser = webBrowser1.PointToScreen(webBrowser1.Location);  //thread-unsafe
                Point p_target = new Point(p_webBrowser.X + webBrowser1.ClientSize.Width / 2 + 7, p_webBrowser.Y + webBrowser1.ClientSize.Height / 2 + 32);  //X+ 7, Y +32

                Graphics.FromImage(b).CopyFromScreen(p_target, new Point(0, 0), webBrowser1.ClientSize);  //src, dst, size
                
                //String filename = GlobalParameters.working_directory + @"\test.jpg";  //截图暂存
                //b.Save(filename);

                m_captcha = new CaptchaImage(b);  //用截图得到的验证码图片,初始化CaptchaImage实例
                m_captcha_numbers = m_captcha.GetCaptchaWrapper();
                b.Dispose();
            }
有类似问题的朋友主需要关心if-else这个结构就可以了,不需要细看代码。if是定时器线程执行,其中创建一个委托实例,而后委托主线程执行。
crystal_lz 2016-03-18
  • 打赏
  • 举报
回复
在你的 elem_signIn.FirstChild.InvokeMember("click") 前面一句加上一句 elem_signIn.FirstChild.Click += 你绑定的事件 你自己绑定的事件上去 肯定是在 对应元素的事件队列末尾 也就是会先执行元素原本绑定的 click 事件的时候 最后才会触发你绑定的 click 事件 而执行你绑定的 click 事件的时候 页面原本绑定的 click 事件已经执行完成 所以你的事件 就可以当作是一个通知
秋的红果实 2016-03-17
  • 打赏
  • 举报
回复
截图前System.Threading.Thread.Sleep(1000),停1秒钟
Poopaye 2016-03-17
  • 打赏
  • 举报
回复
创建个Timer等1秒再截图,此时事件就退出了
kelsius 2016-03-17
  • 打赏
  • 举报
回复
引用 1 楼 shingoscar 的回复:
等上1、2秒再截图不就行了
我尝试过,但好像只有webBrowser_DocumentCompleted函数退出后,“签到框”才会弹出。有种“缓冲”的错觉。好比cout<<"hello";不加endl是不会刷新缓冲区立即输出一样。 比较困惑。
Poopaye 2016-03-17
  • 打赏
  • 举报
回复
等上1、2秒再截图不就行了

111,129

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧