• 前言

      在 Window Form 应用程序如果需要浏览网页时可以崁入 WebBrowser 控件,但如果需要操作崁入的 HTML 的网页元素,就需要额外的操作,以下纪录几种操作 HTML 元素的方法以及会碰到的问题。

    建立 WinForm 应用程序

      首先先建立一个 Window Form 应用程序,在 Form1 窗体上拉入一个 Button 与 WebBrowser 控件,如下


     
    在 Button1 事件中使用 WebBrowser.Navigate 方法加载指定的网页,如下

    1.private void button1_Click(object sender, EventArgs e)
    2.{
    3.webBrowser1.Navigate(Application.StartupPath + "\\Page.html");
    4.}

    直接执行程序后点击「前往网页」按钮就能够看到网页已经加载 WebBrowser 控件中,如下

    操作 HTML 网页中的元素

      接下来如需要针对 HTML 网页上的元素进行控制时,可以透过 WebBrowser
    控件提供的方法来处理,首先要在网页加载完成后才进行操作,点选 WebBrowser 控件加入 DocumentCompleted
    事件,DocumentCompleted 事件是当网页文件完全加载后即会触发,就可以透过 Document、DocumentText、或
    DocumentStream 属性取得网页内容,如下。

    01.private void webBrowser1_DocumentCompleted
    02.(object sender, WebBrowserDocumentCompletedEventArgs e)
    03.{
    04.if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
    05.{
    06.ThreadPool.QueueUserWorkItem(o =>
    07.{
    08.FormWork();
    09.});
    10.}
    11.}
    12. 
    13.private void FormWork()
    14.{
    15.// 進行操作
    16.}

      透过 WebBrowser.ReadyState 属性可以知道网页使否已经加载完成,当加载完成后就使用 Thread 委派 FormWork 方法来处理网页元素的操作,相关操作方法以下列出几项。

    操作文字框

    1.webBrowser1.Document.GetElementById("name").SetAttribute("value", "Arvin");

    操作下拉选单

    1.HtmlElementCollection opts = webBrowser1.Document.
    2.GetElementById("sex").GetElementsByTagName("option");
    3.foreach (HtmlElement opt in opts)
    4.{
    5.if (opt.GetAttribute("value") == "男")
    6.opt.SetAttribute("selected", "selected");
    7.}

    操作单选框

    1.HtmlElementCollection opts = webBrowser1.Document.
    2.GetElementsByTagName("input").GetElementsByName("skill");
    3.foreach (HtmlElement opt in opts)
    4.{
    5.if (opt.GetAttribute("value") == "WebForm")
    6.opt.InvokeMember("click");
    7.}

    执行 JavaScript 方法 (不需写入左右括号符号)

    1.webBrowser1.Document.InvokeScript("ShowInfo");

    取得网页内崁 iFrame 网页的内容方法

    1.webBrowser1.Document.Window.Frames[0].Document

      以上列出几种操作网页元素的做法,不外乎就是取得元素对象再透过 SetAttribute 方法来取得或设定值,最后将几种操作方式组合后来测试自动输入窗体的功能并且希望输入窗体时能够一步一步输入,所以加入 Sleep 方法停顿一秒钟,如下

    01.private void FormWork()
    02.{
    03.webBrowser1.Document.GetElementById("name").SetAttribute("value", "Arvin");
    04.Thread.Sleep(1000);
    05. 
    06.webBrowser1.Document.GetElementById("phone").SetAttribute("value", "0912345678");
    07.Thread.Sleep(1000);
    08. 
    09.HtmlElementCollection opts = webBrowser1.Document.
    10.GetElementById("sex").GetElementsByTagName("option");
    11.foreach (HtmlElement opt in opts)
    12.{
    13.if (opt.GetAttribute("value") == "男")
    14.opt.SetAttribute("selected", "selected");
    15.}
    16.Thread.Sleep(1000);
    17. 
    18.HtmlElementCollection opts2 = webBrowser1.Document.
    19.GetElementsByTagName("input").GetElementsByName("skill");
    20.foreach (HtmlElement opt in opts2)
    21.{
    22.if (opt.GetAttribute("value") == "WebForm")
    23.opt.InvokeMember("click");
    24.}
    25.Thread.Sleep(1000);
    26. 
    27.webBrowser1.Document.InvokeScript("ShowInfo");
    28.}

    完成后执行程序代码上就会跳出 InvalidCastException 错误,如下

      其原因是因为执行绪安全的关系,无法在非主执行绪的线程下操作 UI 控件,在以上的程序代码中直接在 Thread 方法中取得 webBrowser1 控件进行操作因而导致了错误发生。

      调整程序代码先使用 Control.InvokeRequired 属性来判断是否在主执行绪下执行,若不是的话则呼叫 Invoke 方法指定委派,如下。

    01.private delegate void FormWorkDelegate();
    02. 
    03.private void FormWork()
    04.{
    05.if (webBrowser1.InvokeRequired)
    06.webBrowser1.Invoke(new FormWorkDelegate(FormWork));
    07.else
    08.{
    09.webBrowser1.Document.GetElementById("name").SetAttribute("value", "Arvin");
    10.Thread.Sleep(1000);
    11. 
    12.webBrowser1.Document.GetElementById("phone").SetAttribute("value", "0912345678");
    13.Thread.Sleep(1000);
    14. 
    15.HtmlElementCollection opts = webBrowser1.Document.
    16.GetElementById("sex").GetElementsByTagName("option");
    17.foreach (HtmlElement opt in opts)
    18.{
    19.if (opt.GetAttribute("value") == "男")
    20.opt.SetAttribute("selected", "selected");
    21.}
    22.Thread.Sleep(1000);
    23. 
    24.HtmlElementCollection opts2 = webBrowser1.Document.
    25.GetElementsByTagName("input").GetElementsByName("skill");
    26.foreach (HtmlElement opt in opts2)
    27.{
    28.if (opt.GetAttribute("value") == "WebForm")
    29.opt.InvokeMember("click");
    30.}
    31.Thread.Sleep(1000);
    32. 
    33.webBrowser1.Document.InvokeScript("ShowInfo");
    34.}
    35.}

      在次执行后发现不会跳出错误讯息了,但是却发生另一个问题,就是当页面加载后在填入窗体值时程序会停顿一段时候才一次显示所以字段的值,这样的结果并不符合当初所要一步一步的填入窗体的需求,如下

      这种问题在我此篇MSDN发问中 ThankfulHeart 大有提到,Invoke 方法是使用 UI 的线程,而如果在 UI 线程中使用了 Sleep 方法将导致 UI 画面被阻塞,因此才让画面陷入了停顿的状态。

      而在 FormWork 方法中我将操作的方法都包含在 Invoke 的程序区块中,所以在此如要避免长时间的画面阻塞,应该要尽可能的切割使用到 Invoke 的区段,因此修改程序如下。

    01.private void FormWork()
    02.{
    03.this.Invoke(new MethodInvoker(() =>
    04.{
    05.webBrowser1.Document.GetElementById("name").SetAttribute("value", "Arvin");
    06.}));
    07.Thread.Sleep(1000);
    08. 
    09.this.Invoke(new MethodInvoker(() =>
    10.{
    11.webBrowser1.Document.GetElementById("phone").SetAttribute("value", "0912345678");
    12.}));
    13.Thread.Sleep(1000);
    14. 
    15.this.Invoke(new MethodInvoker(() =>
    16.{
    17.HtmlElementCollection opts = webBrowser1.Document.
    18.GetElementById("sex").GetElementsByTagName("option");
    19.foreach (HtmlElement opt in opts)
    20.{
    21.if (opt.GetAttribute("value") == "男")
    22.opt.SetAttribute("selected", "selected");
    23.}
    24.}));
    25.Thread.Sleep(1000);
    26. 
    27.this.Invoke(new MethodInvoker(() =>
    28.{
    29.HtmlElementCollection opts2 = webBrowser1.Document.
    30.GetElementsByTagName("input").GetElementsByName("skill");
    31.foreach (HtmlElement opt in opts2)
    32.{
    33.if (opt.GetAttribute("value") == "WebForm")
    34.opt.InvokeMember("click");
    35.}
    36.}));
    37.Thread.Sleep(1000);
    38. 
    39.this.Invoke(new MethodInvoker(() =>
    40.{
    41.webBrowser1.Document.InvokeScript("ShowInfo");
    42.}));
    43.}

    透过切割每个动作呼叫对应的 Invoke 去执行后执行结果如下

     以上就是一个简单使用 WinForm 的 WebBrowser 控件控制网页元素的方式,在此纪录一下做法。

    范例程序代码

    http://www.it165.net/uploadfile/2013/1017/20131017072343466.rar
     

WinForm使用WebBrowser操作HTML页面的Element的更多相关文章

  1. [WinForm] 使用 WebBrowser 操作 HTML 頁面的 Element-摘自网络

    前言 在 Window Form 應用程式如果需要瀏覽網頁時可以崁入 WebBrowser 控制項,但如果需要操作崁入的 HTML 的網頁元素,就需要額外的操作,以下紀錄幾種操作 HTML 元素的方法 ...

  2. jquery的常用操作(操作html页面的Dom对象的元素)

    一:页面加载完成时,会执行jquery的方法(不需要等待图片加载完成,只要dom结构加载完成,就执行该方法) //第一种写法: $(document).ready(function() { // 执行 ...

  3. 浏览器操作html页面的width和height

    原文:http://www.cnblogs.com/dengshunping/archive/2009/06/15/1503803.html IE中: document.body.clientWidt ...

  4. [react] 什么是虚拟dom?虚拟dom比操作原生dom要快吗?虚拟dom是如何转变成真实dom并渲染到页面的?

    壹 ❀ 引 虚拟DOM(Virtual DOM)在前端领域也算是老生常谈的话题了,若你了解过vue或者react一定避不开这个话题,因此虚拟DOM也算是面试中常问的一个点,那么通过本文,你将了解到如下 ...

  5. 高并发分布式系统中生成全局唯一(订单号)Id js返回上一页并刷新、返回上一页、自动刷新页面 父页面操作嵌套iframe子页面的HTML标签元素 .net判断System.Data.DataRow中是否包含某列 .Net使用system.Security.Cryptography.RNGCryptoServiceProvider类与System.Random类生成随机数

    高并发分布式系统中生成全局唯一(订单号)Id   1.GUID数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么通过组合的方式,保留GUID的10个字节,用另6个字节表示GUID生成的时间(D ...

  6. WebBrowser之获取跳转页面的Document接口源码

    问题由来是这样的,今天帮一个网友解决问题,说从VC驿站下载了一个源码,程序的功能主要是在对话框上面放置了一个WebBrowser控件,程序启动的时候默认调用这句代码: m_web.Navigate(_ ...

  7. 为WebBrowser的WEB页的Document注册事件的问题

    原文:为WebBrowser的WEB页的Document注册事件的问题 当使用WebBrowser,并对其装载的Web页建立Document的事件后,WebBrowser里的页面元素都变得难于操作了, ...

  8. .Net2.0 --Winform结合WebBrowser控件和Socket老技术来实现另类Push~

    原文:.Net2.0 --Winform结合WebBrowser控件和Socket老技术来实现另类Push~ 目前的企业级开发比较流行的是Web2.0技术,但是由于Web技术基于请求--响应的交互模式 ...

  9. C# winform调用WebBrowser经典怪问题总结

    原文:C# winform调用WebBrowser经典怪问题总结 最近一直研究网页数据采集,单单采集数据,其实HtmlAgilityPack就足够了. 对HtmlAgilityPack感兴趣的可以到这 ...

随机推荐

  1. 如何让VS2013编写的程序

    总体分c++程序和c#程序 1.c++程序 这个用C++编写的程序可以经过设置后在XP下运行,主要的“平台工具集”里修改就可以. 额外说明:(1)程序必须为Dotnet 4.0及以下版本.(XP只支持 ...

  2. Hibernate双向多对多对象关系模型映射

    1 双向many-to-many 业务模型: 描述员工和项目 一个员工同时可以参与多个项目 一个项目中可以包含多个员工 分析:数据库的数据模型,通过中间关系表,建立两个one-to-many构成man ...

  3. stdafx.h的作用

    // stdafx.h : include file for standard system include files,// or project specific include files th ...

  4. qt_计算器的简单实现

    //阶乘不知道怎么实现不了/(ㄒoㄒ)/~~,以后慢慢调试吧......... //转换为后缀表达式,实现最主要功能 void MainWindow::toPostfix () { QString e ...

  5. Java遍历List的时候删除item

    参考:http://blog.csdn.net/longyulu/article/details/8315068 在Java中有时候我们会需要对List里面的符合某种业务的数据进行删除,但是如果不了解 ...

  6. 384. Shuffle an Array

    Shuffle a set of numbers without duplicates. Example: // Init an array with set 1, 2, and 3. int[] n ...

  7. Android缓存学习入门

    本文主要包括以下内容 利用LruCache实现内存缓存 利用DiskLruCache实现磁盘缓存 LruCache与DiskLruCache结合实例 利用了缓存机制的瀑布流实例 内存缓存的实现 pub ...

  8. #Mac技巧#如何在Mac系统上新建TXT文档,以及打开txt文稿的乱码问题如何解决

    使用mac的朋友可能都有这样的疑问,mac系统下强大的文本编辑器居然不能保存常用的TXT格式? 又或者打开同事在windows上保存的TXT文件会出现如下情况: 最近Hans也被这些问题困扰着,于是便 ...

  9. C#回顾 – 4.IEnumerable 集合

         

  10. Jquery自定义图片上传插件

    1 概述 编写后台网站程序大多数用到文件上传,可是传统的文件上传控件不是外观不够优雅,就是性能不太好看,翻阅众多文件上传控件的文章,发现可以这样去定义一个文件上传控件,实现的文件上传的效果图如下: 2 ...