前言
在 Window Form 應用程式如果需要瀏覽網頁時可以崁入 WebBrowser 控制項,但如果需要操作崁入的 HTML 的網頁元素,就需要額外的操作,以下紀錄幾種操作 HTML 元素的方法以及會碰到的問題。
建立 WinForm 應用程式
首先先建立一個 Window Form 應用程式,在 Form1 表單上拉入一個 Button 與 WebBrowser 控制項,如下

在 Button1 事件中使用 WebBrowser.Navigate 方法載入指定的網頁,如下
1 |
private void button1_Click( object sender, EventArgs e) |
3 |
webBrowser1.Navigate(Application.StartupPath + "\\Page.html" ); |
直接執行程式後點擊「前往網頁」按鈕就能夠看到網頁已經載入 WebBrowser 控制項中,如下

操作 HTML 網頁中的元素
接下來如需要針對 HTML 網頁上的元素進行控制時,可以透過 WebBrowser 控制項提供的方法來處理,首先要在網頁載入完成後才進行操作,點選 WebBrowser 控制項加入 DocumentCompleted 事件,DocumentCompleted 事件是當網頁文件完全載入後即會觸發,就可以透過 Document、DocumentText、或 DocumentStream 屬性取得網頁內容,如下。
01 |
private void webBrowser1_DocumentCompleted |
02 |
( object sender, WebBrowserDocumentCompletedEventArgs e) |
04 |
if (webBrowser1.ReadyState == WebBrowserReadyState.Complete) |
06 |
ThreadPool.QueueUserWorkItem(o => |
13 |
private void FormWork() |
透過 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) |
5 |
if (opt.GetAttribute( "value" ) == "男" ) |
6 |
opt.SetAttribute( "selected" , "selected" ); |
操作單選框
1 |
HtmlElementCollection opts = webBrowser1.Document. |
2 |
GetElementsByTagName( "input" ).GetElementsByName( "skill" ); |
3 |
foreach (HtmlElement opt in opts) |
5 |
if (opt.GetAttribute( "value" ) == "WebForm" ) |
6 |
opt.InvokeMember( "click" ); |
執行 JavaScript 方法 (不需寫入左右括弧符號)
1 |
webBrowser1.Document.InvokeScript( "ShowInfo" ); |
取得網頁內崁 iFrame 網頁的內容方法
1 |
webBrowser1.Document.Window.Frames[0].Document |
以上列出幾種操作網頁元素的做法,不外乎就是取得元素物件再透過 SetAttribute 方法來取得或設定值,最後將幾種操作方式組合後來測試自動輸入表單的功能並且希望輸入表單時能夠一步一步輸入,所以加入 Sleep 方法停頓一秒鐘,如下
01 |
private void FormWork() |
03 |
webBrowser1.Document.GetElementById( "name" ).SetAttribute( "value" , "Arvin" ); |
06 |
webBrowser1.Document.GetElementById( "phone" ).SetAttribute( "value" , "0912345678" ); |
09 |
HtmlElementCollection opts = webBrowser1.Document. |
10 |
GetElementById( "sex" ).GetElementsByTagName( "option" ); |
11 |
foreach (HtmlElement opt in opts) |
13 |
if (opt.GetAttribute( "value" ) == "男" ) |
14 |
opt.SetAttribute( "selected" , "selected" ); |
18 |
HtmlElementCollection opts2 = webBrowser1.Document. |
19 |
GetElementsByTagName( "input" ).GetElementsByName( "skill" ); |
20 |
foreach (HtmlElement opt in opts2) |
22 |
if (opt.GetAttribute( "value" ) == "WebForm" ) |
23 |
opt.InvokeMember( "click" ); |
27 |
webBrowser1.Document.InvokeScript( "ShowInfo" ); |
完成後執行程式碼上就會跳出 InvalidCastException 錯誤,如下

其原因是因為執行緒安全的關係,無法在非主執行緒的線程下操作 UI 控制項,在以上的程式碼中直接在 Thread 方法中取得 webBrowser1 控制項進行操作因而導致了錯誤發生。
調整程式碼先使用 Control.InvokeRequired 屬性來判斷是否在主執行緒下執行,若不是的話則呼叫 Invoke 方法指定委派,如下。
01 |
private delegate void FormWorkDelegate(); |
03 |
private void FormWork() |
05 |
if (webBrowser1.InvokeRequired) |
06 |
webBrowser1.Invoke( new FormWorkDelegate(FormWork)); |
09 |
webBrowser1.Document.GetElementById( "name" ).SetAttribute( "value" , "Arvin" ); |
12 |
webBrowser1.Document.GetElementById( "phone" ).SetAttribute( "value" , "0912345678" ); |
15 |
HtmlElementCollection opts = webBrowser1.Document. |
16 |
GetElementById( "sex" ).GetElementsByTagName( "option" ); |
17 |
foreach (HtmlElement opt in opts) |
19 |
if (opt.GetAttribute( "value" ) == "男" ) |
20 |
opt.SetAttribute( "selected" , "selected" ); |
24 |
HtmlElementCollection opts2 = webBrowser1.Document. |
25 |
GetElementsByTagName( "input" ).GetElementsByName( "skill" ); |
26 |
foreach (HtmlElement opt in opts2) |
28 |
if (opt.GetAttribute( "value" ) == "WebForm" ) |
29 |
opt.InvokeMember( "click" ); |
33 |
webBrowser1.Document.InvokeScript( "ShowInfo" ); |
在次執行後發現不會跳出錯誤訊息了,但是卻發生另一個問題,就是當頁面載入後在填入表單值時程式會停頓一段時候才一次顯示所以欄位的值,這樣的結果並不符合當初所要一步一步的填入表單的需求,如下

這種問題在我此篇MSDN發問中 ThankfulHeart 大有提到,Invoke 方法是使用 UI 的線程,而如果在 UI 線程中使用了 Sleep 方法將導致 UI 畫面被阻塞,因此才讓畫面陷入了停頓的狀態。
而在 FormWork 方法中我將操作的方法都包含在 Invoke 的程式區塊中,所以在此如要避免長時間的畫面阻塞,應該要盡可能的切割使用到 Invoke 的區段,因此修改程式如下。
01 |
private void FormWork() |
03 |
this .Invoke( new MethodInvoker(() => |
05 |
webBrowser1.Document.GetElementById( "name" ).SetAttribute( "value" , "Arvin" ); |
09 |
this .Invoke( new MethodInvoker(() => |
11 |
webBrowser1.Document.GetElementById( "phone" ).SetAttribute( "value" , "0912345678" ); |
15 |
this .Invoke( new MethodInvoker(() => |
17 |
HtmlElementCollection opts = webBrowser1.Document. |
18 |
GetElementById( "sex" ).GetElementsByTagName( "option" ); |
19 |
foreach (HtmlElement opt in opts) |
21 |
if (opt.GetAttribute( "value" ) == "男" ) |
22 |
opt.SetAttribute( "selected" , "selected" ); |
27 |
this .Invoke( new MethodInvoker(() => |
29 |
HtmlElementCollection opts2 = webBrowser1.Document. |
30 |
GetElementsByTagName( "input" ).GetElementsByName( "skill" ); |
31 |
foreach (HtmlElement opt in opts2) |
33 |
if (opt.GetAttribute( "value" ) == "WebForm" ) |
34 |
opt.InvokeMember( "click" ); |
39 |
this .Invoke( new MethodInvoker(() => |
41 |
webBrowser1.Document.InvokeScript( "ShowInfo" ); |
透過切割每個動作呼叫對應的 Invoke 去執行後執行結果如下

以上就是一個簡單使用 WinForm 的 WebBrowser 控制項控制網頁元素的方式,在此紀錄一下做法。
範例程式碼
WinWebBrowser.rar
- WinForm使用WebBrowser操作HTML页面的Element
前言 在 Window Form 应用程序如果需要浏览网页时可以崁入 WebBrowser 控件,但如果需要操作崁入的 HTML 的网页元素,就需要额外的操作,以下纪录几种操作 HTML 元素的方法以 ...
- Ubuntu的复制粘贴操作及常用快捷键(摘自网络)
Ubuntu的复制粘贴操作 终端最大化快捷键:crtl + win + 上 1.最为简单,最为常用的应该是鼠标右键操作了,可以选中文件,字符等,右键鼠标,复制,到目的地右键鼠标,粘贴就结束了. 2.快 ...
- HttpWebRequest post 提交 C#的WebBrowser操作frame如此简单 WebClient 提交
//http://www.cnblogs.com/cgli/archive/2011/04/09/2010497.html System.Net.ServicePointManager.Expect1 ...
- C#的WebBrowser操作frame
刚学c#不久,也不太懂什么IHTMLDocument.IHTMLDocument2.IWebBrowser2等等.自己琢磨了好久,终于知道了怎么用WebBrowser操作frame和iframe. 1 ...
- .Net2.0 --Winform结合WebBrowser控件和Socket老技术来实现另类Push~
原文:.Net2.0 --Winform结合WebBrowser控件和Socket老技术来实现另类Push~ 目前的企业级开发比较流行的是Web2.0技术,但是由于Web技术基于请求--响应的交互模式 ...
- C# winform调用WebBrowser经典怪问题总结
原文:C# winform调用WebBrowser经典怪问题总结 最近一直研究网页数据采集,单单采集数据,其实HtmlAgilityPack就足够了. 对HtmlAgilityPack感兴趣的可以到这 ...
- 浏览器自动化的一些体会5 webBrowser控件之winform和webBrowser的交互
从winform访问webBrowser,大致就是利用webBrowser提供的解析dom的方法以及用InvokeScript方法执行javascript.这个相对比较简单. 从webBrowser访 ...
- WinForm中WebBrowser的使用
最近由于工作需要,研究了下Winform的WebBrowser控件,在这里给大家分享下. 1.WebBrowser导航 WebBrowser在进行导航的时候需要用到Navigate(string ur ...
- C#的WebBrowser操作frame如此简单
刚学c#不久,也不太懂什么IHTMLDocument.IHTMLDocument2.IWebBrowser2等等.自己琢磨了好久,终于知道了怎么用WebBrowser操作frame和iframe. 1 ...
随机推荐
- [HDOJ2512]一卡通大冒险(DP)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2512 给一个数n,问1~n这n个数内的划分.设dp(i,j)为i划分为j个集合时有多少个. 初始化条件 ...
- Linux常用到的指令汇总
Linux常用到的指令汇总 根据鸟哥linux私房菜上定义的:一定要先學會的指令:ls, more, cd, pwd, rpm, ifconfig, find 登入與登出(開機與關機):telnet, ...
- ViewState压缩技术
ViewState 的使用,大家可以说是又爱又恨,它其中一个特性就是保存页面的状态,对于只是展示的页面,我们可以直接在页面文件中使用 EnableViewState="false" ...
- java 名词解释等
类 实例 引用 实质指针 封装 for 的不同形式 for (int i : Location) 集合类 ArrayList<Egg> = new ArrayList<Egg> ...
- Python3 学习第十二弹: 补充something
python中遇到 *keys, **keys的形式 其实 * 代表传递任意个无名字参数,这些参数通过Tuple访问 >>> def sum(*keys): ret= 0 for i ...
- linux下从源代码安装git
之所以有这样的需求,是因为部分预安装的git版本太低,很多功能没有并且安全性存在问题. 比如git submodule add xxx@host:yyy.git必须在父repo的root目录安装,而新 ...
- EntityFramework:支持同一事务提交的批量删除数据实现思路
一切从一段代码说起... 下面一段代码是最近我在对一EF项目进行重构时发现的. protected override void DoRemove(T entity) { this.dbContext. ...
- (转) error: linker command failed with exit code 1 (use -v to see invocation)
转自:http://blog.csdn.net/tiantian1980/article/details/9175777 像这样的一大堆,总体说编译链接时错误 /Users/zhangtianji ...
- 20160201.CCPP体系详解(0011天)
内容概要:C语言基本数据类型及运算题库(含答案) 第二章 基本数据类型及运算 一.选择题 1. 若以下选项中的变量已正确定义,则正确的赋值语句是[C]. A) x1=26.8%3; B) 1+2=x2 ...
- Activiti 多个并发子流程的应用
多个部门发起资金计划,最后统一到财务部审批,每个部门发起资金计划是一个子流程,财务部审批是多个部门的计划同时审批,审批完成后,再提交上级领导审批. 流程如下: 要解决以上问题,需要实现多个子流程并行处 ...