浏览器自动化的一些体会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 = ; 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 > )
{
MessageBox.Show("网络有问题,请换个时间再试");
return;
}
_waitCount++;
timer1.Start();
return;//继续等
} _waitCount = ;//复原
//“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毫秒
{
Application.DoEvents();
}
写博客很费时间。webBrower控件还有许多要谈的问题,以后再写。
浏览器自动化的一些体会2 webBrowser控件之ajax的更多相关文章
- 浏览器自动化的一些体会9 webBrowser控件之零碎问题3
WebBrowser控件最大的优点是可以轻松嵌入win form程序中,但是微软好像对这个控件没什么兴趣,这么多年了还没有改进,结果造成一堆问题. 1. 不支持https 2. 缺省模拟ie 7,如果 ...
- 浏览器自动化的一些体会3 webBrowser控件之零碎问题
1. 一般需要执行这一句:webBrowser1.ScriptErrorsSuppressed = true; 主要目的是禁止跳出javascript错误的对话框,否则会导致程序无法正确地跑下去.缺点 ...
- 浏览器自动化的一些体会5 webBrowser控件之winform和webBrowser的交互
从winform访问webBrowser,大致就是利用webBrowser提供的解析dom的方法以及用InvokeScript方法执行javascript.这个相对比较简单. 从webBrowser访 ...
- 浏览器自动化的一些体会4 webBrowser控件之零碎问题2
1. DocumentCompleted的多次执行问题 有的网页,会多次触发DocumentCompleted事件,由于它是异步的,不会阻塞,所以如果不恰当处理,会造成某些代码被错误地多次执行,造成意 ...
- Webbrowser控件史上最强技巧全集
原文:Webbrowser控件史上最强技巧全集 Webbrowser控件史上最强技巧全集 VB调用webbrowser技巧集 1.获得浏览器信息: Private Sub Command1_Click ...
- WebBrowser控件使用详解
原文:WebBrowser控件使用详解 方法 说明 GoBack 相当于IE的“后退”按钮,使你在当前历史列表中后退一项 GoForward 相当于IE的“前进”按钮,使你在当前历史列表中前进一项 G ...
- 浏览器自动化的一些体会6 增强的webBrowser控件
这里谈两点 1.支持代理服务器切换 一种方法是修改注册表,不是太好的做法,而且,只能改全局设置,不能改局部(比如只让当前的webBrowser控件使用代理,而其他应用不用代理) 另外一个较好的方法,示 ...
- 浏览器自动化的一些体会9 访问angular页面的一个问题
发现浏览器自动化有一个重要方面没有提及,即所谓的无页面浏览器,不过最近没有需求,不想尝试,先记上一笔,以后有需求时,可以有个思路. 大约一两个月前(现在比较懒散,时间不知不觉过去,连今天是几号有时候都 ...
- PB打开ole控件IE浏览器版本问题_指定Webbrowser控件所用IE内核版本(转)
如果电脑上安装了IE8或者之后版本的IE浏览器,Webbrowser控件会使用IE7兼容模式来显示网页内容.解决方法是在注册表中为你的进程指定引用IE的版本号. 比如我的程序叫做a.exe 对于32位 ...
随机推荐
- 读懂操作系统之快表(TLB)原理(七)
前言 前不久.我们详细分析了TLB基本原理,本节我们通过一个简单的示例再次叙述TLB的算法和原理,希望借此示例能加深我们对TLB(又称之为快表,深入理解计算机系统(第三版)又称之为翻译后备缓冲区)的理 ...
- Java 异常处理专题,从入门到精通
内置异常和Throwable核心方法 Java内置异常 可查异常(必须要在方法里面捕获或者抛出) ClassNoFoundException 应⽤程序试图加载类,找不到对应的类 IllegalAcce ...
- fgdsafhak
- Hbase1.2.3安装
HBase是一个分布式,版本化,面向列的数据库,基于Google BigTable模型开发的,典型的key/value系统:构建在HDFS上的分布式列存储系统: 在hadoop master1上安装 ...
- map,reduce,filter基础实现
#coding=gbk from operator import add # 导入加法 # map 函数名 , 序列对象 print(list(map(str,range(5)))) print(li ...
- PHP jdtogregorian() 函数
------------恢复内容开始------------ 实例 把格利高里历法的日期转换为儒略日计数,然后再转换回格利高里历法的日期: <?php$jd=gregoriantojd(6,20 ...
- PHP zip_entry_compressionmethod() 函数
定义和用法 The zip_entry_compressionmethod() 函数返回 zip 档案项目的压缩方法.高佣联盟 www.cgewang.com 语法 zip_entry_compres ...
- PHP metaphone() 函数
实例 计算 "World" 的 metaphone 键: <?php高佣联盟 www.cgewang.comecho metaphone("World") ...
- luogu P4606 [SDOI2018]战略游戏
LINK:战略游戏 一道很有价值的题目.这道题 一张无向联通图 每次询问给出K个关键点 问摧毁图中哪个点可以使得这K个关键的两两之间有一对不能联通 去掉的这个点不能是关键点 求方案数. 可以发现 当K ...
- Elasticsearch和Scala类型转换
Scala Type ES Unit null None null Nil empty array Some[T] according to the table Map object Traver ...