[轉貼] C# WebBrowser實現網頁自動填表

2012111914:49
出處:http://www.cnblogs.com/changyou/archive/2010/01/09/1643094.html

曾經向網友介紹過我的一個自己編寫的自動填寫網頁表單的小程序,很多網友都覺得很實用,也許多會對這個程序的源碼很感興趣,這裡我只是簡介下程序中用到的主要代碼。最初我是通過下面這篇文章漸漸積累的相關知識,再慢慢完善,現轉來同大家分享,共同學習。 

話說有了WebBrowser類,終於不用自己手動封裝SHDocVw的AxWebBrowser這個ActiveX控件了。這個類如果僅僅作為一個和IE一模一樣瀏覽器,那就太沒意思了(還不如直接用IE呢)。那麼,無論我們是想做一個「定制版IE」,還是希望利用HTML來做用戶界面(指WinApp而非WebApp。許多單機軟件,包括Windows的幫助支持中心,都是HTML做的),都少不了Windows Form和包含在WebBrowser中的Web頁面的交互。本文將通過幾個實際的例子,初步介紹一下WinForm和WebBrowser所包含的Web頁面之間的交互。

下面的代碼假設你已經建立了一個Windows Form,上面有一個WebBrowser名為「webBrowser」。

Study Case 1:用WinForm的Event Handler響應Web頁面的事件

現在有這樣一個Windows Application,它的界面上只有一個WebBrowser,顯示一個本地的HTML文件作為界面。現在的問題是,所有邏輯都可以放在HTML文件裡,唯獨「關閉」按鈕遇到了困難——通常,Web頁面是沒有辦法直接控制瀏覽器的,更不用說結束這個WinForm程序了。

但是,在.Net 2.0當中,「由Windows Form響應Web頁面的事件」已經成為了現實。

在.Net 2.0中,整個HTML文檔以及其包含的各個HTML元素,都和一個個HtmlDocument、HtmlElement之類的.Net對象對應。因此只要找到這個「關閉」按鈕對應的HtmlElement對象,為其click事件添加Event Handler即可。 
假設HTML源代碼如下:


 
 
 

那麼找出該按鈕並為之添加Event Handler的代碼如下:

HtmlDocument htmlDoc = webBrowser.Document; 
HtmlElement btnElement = htmlDoc.All["btnClose"]; 
if (btnElement != null) 
{ 
btnElement.click += new HtmlElementEventHandler(HtmlBtnClose_Click); 
}

其中HtmlBtnClose_Click是按下Web按鈕時的Event Handler。

很簡單吧?那麼稍稍高級一點的——我們都知道一個HTML元素可能有很多各種各樣的事件,而HtmlElement這個類只給出最常用、共通的幾個。那麼,如何響應其他事件呢?這也很簡單,只需要調用HtmlElement的AttachEventHandler就可以了:

btnElement.AttachEventHandler("onclick", new EventHandler(HtmlBtnClose_Click)); 
//這一句等價於上面的btnElement.click += new HtmlElementEventHandler(HtmlBtnClose_Click);

對於其他事件,把"onclick"換成該事件的名字就可以了。例如:

formElement.AttachEventHandler("onsubmit", new EventHandler(HtmlForm_Submit));

Study Case 2:表單(form)的自動填寫和提交 
要使我們的WebBrowser具有自動填表、甚至自動提交的功能,並不困難。

假設有一個最簡單的登錄頁面,輸入用戶名密碼,點「登錄」按鈕即可登錄。已知用戶名輸入框的id(或Name,下同)是username,密碼輸入框的id是password,「登錄」按鈕的id是submitbutton,那麼我們只需要在webBrowser的DocumentCompleted事件中使用下面的代碼即可:

HtmlElement btnSubmit = webBrowser.Document.All["submitbutton"]; 
HtmlElement tbUserid = webBrowser.Document.All["username"]; 
HtmlElement tbPasswd = webBrowser.Document.All["password"]; 
if (tbUserid == null || tbPasswd == null || btnSubmit == null) 
return; 
tbUserid.SetAttribute("value", "smalldust"); 
tbPasswd.SetAttribute("value", "12345678"); 
btnSubmit.InvokeMember("click");

這裡我們用SetAttribute來設置文本框的「value」屬性,用InvokeMember來調用了按鈕的「click」方法。因為不同的Html元素,其擁有的屬性和方法也不盡相同,所以.Net 2.0提供了統一的HtmlElement來概括各種Html元素的同時,提供了這兩個方法以調用元素特有的功能。關於各種Html元素的屬性和方法一覽,可以查閱MSDN的DHTML Reference

※關於表單的提交,的確還有另一種方法就是獲取form元素而不是button,並用form元素的submit方法:

HtmlElement formLogin = webBrowser.Document.Forms["loginForm"]; 
//…… 
formLogin.InvokeMember("submit");

本文之所以沒有推薦這種方法,是因為現在的網頁,很多都在submit按鈕上添加onclick事件,以對提交的內容做最基本的驗證。如果直接使用form的submit方法,這些驗證代碼就得不到執行,有可能會引起錯誤。 
Study Case 3:查找並選擇文本 
這次我們希望實現一個和IE一模一樣的查找功能,以對Web頁面內的文字進行查找。

文本查找要借助於TextRange對象的findText方法。但是,.Net裡並沒有這個對象。這是因為,.Net 2.0提供的HtmlDocument,HtmlWindow,HtmlElement等類,只不過是對原有mshtml這個COM組件的不完整封裝,只提供了mshtml的部分功能。所以許多時候,我們仍舊要借助mshtml來實現我們需要的功能。好在這些.Net類都提供了DomDocument這個屬性,使得我們很容易把.Net對象轉換為COM對象使用。下面的代碼演示了如何查找Web頁面的文本。 
(需要添加mshtml的引用,並加上using mshtml;)

public partial class SearchDemo : Form 
{ 
// 建立一個查找用的TextRange(IHTMLTxtRange接口) 
private IHTMLTxtRange searchRange = null; 
public SearchDemo() 
{ 
InitializeComponent(); 
} 
private void btnSearch_Click(object sender, EventArgs e) 
{ 
// Document的DomDocument屬性,就是該對象內部的COM對象。 
IHTMLDocument2 document = (IHTMLDocument2)webBrowser.Document.DomDocument; 
string keyword = txtKeyword.Text.Trim(); 
if (keyword == "") 
return; 
// IE的查找邏輯就是,如果有選區,就從當前選區開頭+1字符處開始查找;沒有的話就從頁面最初開始查找。 
// 這個邏輯其實是有點不大恰當的,我們這裡不用管,和IE一致即可。 
if (document.selection.type.ToLower() != "none") 
{ 
searchRange = (IHTMLTxtRange)document.selection.createRange(); 
searchRange.collapse(true); 
searchRange.moveStart("character", 1); 
} 
else 
{ 
IHTMLBodyElement body = (IHTMLBodyElement)document.body; 
searchRange = (IHTMLTxtRange)body.createTextRange(); 
} 
// 如果找到了,就選取(高亮顯示)該關鍵字;否則彈出消息。 
if (searchRange.findText(keyword, 1, 0)) 
{ 
searchRange.select(); 
} 
else 
{ 
MessageBox.Show("已搜索到文檔結尾。"); 
} 
} 
}

到此為止,簡單的查找就搞定了。至於替換功能,看了下一個例子,我相信你就可以觸類旁通輕松搞定了。