浏览器自动化的一些体会2 webBrowser控件之ajax

上个帖子简要讨论了浏览器自动化的几种方法。现在讨论webBrowser控件使用中的一些问题。基本的操作就不详细说了,随便网上找个帖子或找本书都有介绍的。这里只写点网上似乎少有人总结过的内容,以及自己的一些实践体会。

1.ajax

首先,DocumentCompleted事件对于ajax无能为力,因为这个事件不能处理网页加载完成后执行javascript发出ajax请求。网上可以找到的方法,主要有两种,一种是利用onpropertychange事件,随便找了个参考链接:https://social.msdn.microsoft.com/Forums/ie/en-US/5fe3e7a1-b3c7-4083-9a00-7a72bf833a9c/ajax-detection-in-webbrowser-control?forum=ieextensiondevelopment , 另外一种就是用timer。

实践中的体会是onpropertychange也不好用,timer比较好使。timer在这里的本质就是延时。我一般有两种做法,一种是在DocumentCompleted事件处理代码里启动timer

即:

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
      timer1.Stop();
      timer1.Start();
}

这里先Stop再Start不过是个人的一个习惯,很多情况下没必要。但是如果一个timer已经启动了,则需要先Stop再Start。

另一种是在启动webbrowser.Navigate的代码里启动timer:

private void button1_Click(object sender, EventArgs e)
{
        webBrowser1.Navigate(“foo.com");
        timer1.Stop();
        timer1.Start();
}

个人更喜欢第2种方式,理由是DocumentCompleted里面尽量不用很多代码,主要原因是有些情况下DocumentCompleted事件会被多次触发,所以如果没有正确处理好这种情况,有些代码就会被重复执行,造成意想不到的结果。但是,后一种做法也有缺点,因为不是在DocumentCompleted事件触发后再启动timer,如果网页加载较慢,timer可能会不必要地启动多次。所以还是要看情况处理。

timer1_Tick里的代码大致如此:

private int _waitCount = 0;

private void timer1_Tick(object sender, EventArgs e)
{
      //先stop一般没有什么坏处,而且有些情况下是必要的,比如这里的操作所需时间超过了
      //timer1的间隔(Interval),如果没有stop可能出现意想不到的结果。
      timer1.Stop();
      if (webBrowser1.Document == null
              || webBrowser1.Document.Body == null
              || webBrowser1.Document.GetElementById("foo") == null)
      {
           if (_waitCount > 3)
           {
                 MessageBox.Show("网络有问题,请换个时间再试");
                 return;
           }
           _waitCount++;
           timer1.Start();
           return;//继续等
      }

      _waitCount = 0;//复原
      //“foo”元素检测到,说明ajax请求已返回想要的结果,可以继续下一步处理
      ..............
}

这里用了一个_waitCount的全局变量,目的是为了避免网络有问题,永远加载不完,导致timer代码被反复触发,进入死循环。尝试4次,如果还不行,就提示失败。这里其实牵涉到浏览器自动化的一个重要问题:出错处理。因为网络情况无法预料,所以只有包含良好出错处理的程序,才比较健壮(robust)。网上很多程序,表面看起来work,但遇到出乎意外的网络状况时都会出错,就是因为出错处理做得不好的缘故。这个具体以后再讨论。

前面的if判断条件,如果用新版framework的?语法糖,或许还可写得简单些,这里就不改了。

实践中感到timer的方式主要问题是如果网页里的ajax过多,就需要很多timer,代码显得有点乱。既然timer在这里的作用是延时,那么应该也可用其他方式。

最简单的延时方式,就是Thread.Sleep()。缺点很明显,就是阻塞了主线程,造成假死机现象,用户体验不好。于是有人改良,可参考这个链接:

https://stackoverflow.com/questions/3794522/waiting-for-webbrowser-ajax-content

它用了Application.DoEvents()来避免阻塞。但是,Application.DoEvents()使用要小心,参考这个链接:

https://stackoverflow.com/questions/5181777/use-of-application-doevents

我的理解是,如果允许Application.DoEvents()的时间过长,就容易给用户有机会关掉应用等操作,有可能造成意想不到的结果。而在处理ajax请求时,有可能要等上几秒,几秒是显得有些长了。因此Application.DoEvents()也许在这里用,并不是太好的做法。

另外一种延时方式,虽然并不局限于浏览器自动化里的应用,但既然谈到了,不妨也说一下。这大概是游戏程序里用的较多的,就是类似下面的代码:

var start = Environment.TickCount;
while (Environment.TickCount - start < 100) //延时100毫秒
{
       Application.DoEvents();
}

写博客很费时间。webBrower控件还有许多要谈的问题,以后再写。

原文地址:https://www.cnblogs.com/badnumber/p/8221801.html

时间: 2024-10-15 11:16:22

浏览器自动化的一些体会2 webBrowser控件之ajax的相关文章

浏览器自动化的一些体会4 webBrowser控件之零碎问题2

1. DocumentCompleted的多次执行问题 有的网页,会多次触发DocumentCompleted事件,由于它是异步的,不会阻塞,所以如果不恰当处理,会造成某些代码被错误地多次执行,造成意想不到的结果. 我一般的做法,是定义一个全局变量(winform里form的成员变量),如下面代码所示: private string _type; private void button1_Click(object sender, EventArgs e) { _type = "test"

WebBrowser控件使用详解

WebBrowser控件使用详解 方法 说明 GoBack 相当于IE的“后退”按钮,使你在当前历史列表中后退一项 GoForward 相当于IE的“前进”按钮,使你在当前历史列表中前进一项 GoHome 相当于IE的“主页”按钮,连接用户默认的主页 GoSearch 相当于IE的“搜索”按钮,连接用户默认的搜索页面 Navigate 连接到指定的URL Refresh 刷新当前页面 Refresh2 同上,只是可以指定刷新级别,所指定的刷新级别的值来自RefreshConstants枚举表, 

浏览器自动化的一些体会10 稳定性的零星体会

浏览器自动化程序,感觉最难的就是稳定性.要实现无人值守自动执行,特别是在网络不太好的情况下连续不停顿正常运行8小时或更长时间,是不太容易的.因为很多异常情况难以预料.做好以下几点有帮助: 1)如果是在visual studio下调试,应该把Debug - Exceptions - Managed Debugging Assistants - ContextSwitchDeadLock 的Thrown的打勾去掉,这样可以避免运行到一半,突然出现一个提示,中断程序的执行. 2)如果是用webBrow

通过WebBrowser控件,实现IE浏览器菜单功能

这篇文章所讲的技术,只支持IE浏览器,请读者注意 WebBrowser控件,是IE浏览器的内置控件.顾名思义,这个控件我们可以看成是浏览器本身.通过WebBrowser控件,可以实现一部分IE浏览器的菜单命令. 1. 使用 首先在画面上要通过<object>标签创建这个控件. <OBJECT classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2 height=0 id=WebBrowser width=0></OBJECT>

强制IE浏览器或WebBrowser控件使用指定版本显示网页

强制IE浏览器或WebBrowser控件使用指定版本显示网页 自从装了IE10之后,就发现好些个网站显示都不是那么的正常,网站上有些功能竟然还会出现一些意想不到的BUG——本来就是针对IE开发的,现在IE下竟然用不起来了,让用户情何以堪?但是就为少量用户使用的系统去大动干戈的调整功能,这实在是让人头疼!在经过一番折腾之后,竟然找到一个非常M$的方法来解决 —— 强制高版本的IE浏览器用低地版本模式显示网页. 就是直接让IE10默认以指定的IE版本的浏览器模式来运行,并用这个指定的版本来进行解析页

PB打开ole控件IE浏览器版本问题_指定Webbrowser控件所用IE内核版本(转)

如果电脑上安装了IE8或者之后版本的IE浏览器,Webbrowser控件会使用IE7兼容模式来显示网页内容.解决方法是在注册表中为你的进程指定引用IE的版本号. 比如我的程序叫做a.exe 对于32位程序 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION 对于64位程序 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432No

C# WebBrowser控件使用整理

一.简介 WebBrowser 控件为 WebBrowser ActiveX 控件提供了托管包装. 托管包装使您可以在 Windows 窗体客户端应用程序中显示网页. 使用WebBrowser 控件,可以复制应用程序中的 Internet Explorer Web 浏览功能,还可以禁用默认的 Internet Explorer 功能,并将该控件用作简单的 HTML 文档查看器. 此外,可以使用该控件将基于 DHTML 的用户界面元素添加到窗体中,还可以隐瞒这些元素在 WebBrowser 控件中

Delphi WebBrowser控件的使用(大全 good)

Delphi WebBrowser控件的使用 WebBrowser控件属性:1.Application      如果该对象有效,则返回掌管WebBrowser控件的应用程序实现的自动化对象(IDispatch).如果在宿主对象中自动化对象无效,程序将返回WebBrowser控件的自动化对象2.Parent       返回WebBrowser控件的父自动化对象,通常是一个容器,例如是宿主或IE窗口3.Containe       返回WebBrowser控件容器的自动化对象.通常该值与Pare

C#中的WebBrowser控件的使用

0.常用方法 Navigate(string urlString):浏览urlString表示的网址 Navigate(System.Uri url):浏览url表示的网址 Navigate(string urlString, string targetFrameName, byte[] postData, string additionalHeaders): 浏览urlString表示的网址,并发送postData中的消息 //(通常我们登录一个网站的时候就会把用户名和密码作为postData