前言


  在 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 控制項控制網頁元素的方式,在此紀錄一下做法。

範例程式碼


WinWebBrowser.rar

[WinForm] 使用 WebBrowser 操作 HTML 頁面的 Element-摘自网络的更多相关文章

  1. WinForm使用WebBrowser操作HTML页面的Element

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

  2. Ubuntu的复制粘贴操作及常用快捷键(摘自网络)

    Ubuntu的复制粘贴操作 终端最大化快捷键:crtl + win + 上 1.最为简单,最为常用的应该是鼠标右键操作了,可以选中文件,字符等,右键鼠标,复制,到目的地右键鼠标,粘贴就结束了. 2.快 ...

  3. HttpWebRequest post 提交 C#的WebBrowser操作frame如此简单 WebClient 提交

    //http://www.cnblogs.com/cgli/archive/2011/04/09/2010497.html System.Net.ServicePointManager.Expect1 ...

  4. C#的WebBrowser操作frame

    刚学c#不久,也不太懂什么IHTMLDocument.IHTMLDocument2.IWebBrowser2等等.自己琢磨了好久,终于知道了怎么用WebBrowser操作frame和iframe. 1 ...

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

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

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

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

  7. 浏览器自动化的一些体会5 webBrowser控件之winform和webBrowser的交互

    从winform访问webBrowser,大致就是利用webBrowser提供的解析dom的方法以及用InvokeScript方法执行javascript.这个相对比较简单. 从webBrowser访 ...

  8. WinForm中WebBrowser的使用

    最近由于工作需要,研究了下Winform的WebBrowser控件,在这里给大家分享下. 1.WebBrowser导航 WebBrowser在进行导航的时候需要用到Navigate(string ur ...

  9. C#的WebBrowser操作frame如此简单

    刚学c#不久,也不太懂什么IHTMLDocument.IHTMLDocument2.IWebBrowser2等等.自己琢磨了好久,终于知道了怎么用WebBrowser操作frame和iframe. 1 ...

随机推荐

  1. 关于在c#中引用外部dll文件,在页面中找不到命名空间

    最近在项目中碰到这样的问题,经过搜索,发现是vs2010的版本不对,VS默认的版本是.NET Framework 4 Client Profile,需要将他更改为.NET Framework 4 版本 ...

  2. [NYIST32]组合数(状压,枚举,暴力)

    题目链接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=32 求n个数中挑出r个数字的所有情况,最后倒序输出所有情况. 状压枚举所有情况就是了 ...

  3. Map和hash_map

    map和hash_map 今天在写拼流的程序时碰到一个问题,要根据流的四元组的结构信息映射到该流的数据.也就是我在网络数据包拼接的过程中,要根据包的地址和端口信息,对应到其对应的一个流的数据上去,把端 ...

  4. 维护没有源代码,float改成double

    float f= 931340.31f; Console.WriteLine(f.ToString("#,###,##0.00")); 返回 931,340.30 ,float 1 ...

  5. 4612 warm up tarjan+bfs求树的直径(重边的强连通通分量)忘了写了,今天总结想起来了。

    问加一条边,最少可以剩下几个桥. 先双连通分量缩点,形成一颗树,然后求树的直径,就是减少的桥. 本题要处理重边的情况. 如果本来就两条重边,不能算是桥. 还会爆栈,只能C++交,手动加栈了 别人都是用 ...

  6. 搜索浅谈(Elasticsearch和Lucene4分享)

    刚刚过去的双11,真是给线下运营商好好上了一课.当今的互联网真是炙手可热,大家对互联网的热情是如此之高.相信电商之间的竞争将更加的激烈和残酷,不过,搜索,作为用户体验很重要的一点,各大电商也做的越来越 ...

  7. 转:asmx迷10分钟升级成wcf熟手指南

    前言:本文旨在帮助从未接触过wcf(.svc文件)的webservice开发人员,快速将传统的webService/asmx技术迁移到wcf.高手就不用浪费时间往下看了:) 以下所有操作均为vs201 ...

  8. hihoCoder #1195 高斯消元·一

    题意:便利店老板为了促销,推出了组合包的形式,将不同数量的各类商品打包成一个组合.比如2袋薯片,1听可乐的组合只要5元,而1袋薯片,2听可乐的组合只要4元.通过询问老板知道:一共有N种不同的商品和M种 ...

  9. 利用matlab编写实现显示fmri切片slice图像 混合显示 不同侧面显示 可叠加t检验图显示 by DR. Rajeev Raizada

    1.参考 reference 1. tutorial主页:http://www.bcs.rochester.edu/people/raizada/fmri-matlab.htm. 2.speech_b ...

  10. RNN 与 LSTM 的应用

    之前已经介绍过关于 Recurrent Neural Nnetwork 与 Long Short-Trem Memory 的网络结构与参数求解算法( 递归神经网络(Recurrent Neural N ...