在WebBrowser中通過模擬鍵盤鼠標操控網頁中的文件上傳控件

引言

image 這兩天沉迷了Google SketchUp,剛剛玩夠,一時興起,研究了一下WebBrowser。

我在《WebBrowser控件使用技巧分享》一文中曾談到過“我現在可以通過WebBrowser實現對各種Html元素的操控,唯獨無法控制Html的上傳控件”,出于安全原因,IE沒有對上傳控件提供操控支持,這使得我們沒法像控制其他控件一樣用簡單的代碼進行賦值。

比較實際的解決方案就是模擬操作了,下面我就將演示通過鍵盤、鼠標兩種方式模擬點擊“瀏覽”按鈕,然后配合鍵盤模擬輸入文件路徑,并按回車鍵確認。

初始環境

測試使用了一個簡單的HTML頁面,頁中各個位置中分布了一些文件上傳控件,有些是直接放置的,有些是橫向排列的,有些是嵌套在表格中的,用以測試不同位置的觸發效果:

image?

將此頁面用WebBrowser控件加載。

在程序界面中,我放置了一些控件用于選擇上傳文件所在目錄,測試時首先選定一個包含有文件的目錄,然后從中隨機抽選一個文件填寫到上傳控件中:

image

并在代碼中建立了一個輔助方法,用以讀取頁面上所有的文件上傳控件,在測試時也是從中隨機抽取一個進行操控:

List<HtmlElement> 讀取上傳控件()

{

??? var l = new List<HtmlElement>();

??? foreach (HtmlElement f in webBrowser1.Document.GetElementsByTagName("input"))

??? {

??????? if (f.GetAttribute("type") == "file")

??????? {

??????????? l.Add(f);

??????? }

??? }

??? return l;

}

在類中定義了一個Random類型成員變量用于生成隨機數:

Random R = new Random();

此外還定義了一系列方法,用于在點擊按鈕后,延遲3秒以等待文件瀏覽對話框打開,然后模擬輸入文件路徑,再模擬輸入回車鍵確定:

void 延遲操作對話框(string 填寫文件路徑)

{

??? button1.Enabled = button2.Enabled = button3.Enabled = false;

??? BackgroundWorker b = new BackgroundWorker();

??? b.RunWorkerCompleted += new RunWorkerCompletedEventHandler(b_RunWorkerCompleted);

??? b.DoWork += new DoWorkEventHandler(b_DoWork);

??? b.RunWorkerAsync(填寫文件路徑);

}

?

void b_DoWork(object sender, DoWorkEventArgs e)

{

??? Thread.Sleep(3000);

??? e.Result = e.Argument;

}

?

void b_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

{

??? SendKeys.Send(e.Result as string);

??? SendKeys.Send("{Enter}");

??? button1.Enabled = button2.Enabled = button3.Enabled = true;

}

這里就是通過使用BackgroundWorker組件在后臺延遲3秒,延遲結束后在回調事件中進行操作。

鍵盤模擬方式

先看錄制的動畫:

2009-8-5 23-01-36

在這里首先選擇了一個上傳文件所在目錄,然后進行了幾次鍵盤模擬操作測試。

鍵盤模擬的操作流程如下:

首先激活WebBrowser控件

然后讓文件上傳控件獲取焦點,這時光標會處于文件上傳控件左側的文本框內

模擬輸入Tab鍵切換焦點到“瀏覽..”按鈕

模擬輸入空格鍵點擊該按鈕

然后就是延遲3秒等待文件選取對話框顯示,模擬輸入文件路徑并模擬輸入回車鍵即可

主要代碼如下:

private void button1_Click(object sender, EventArgs e)

{

??? var l = 讀取上傳控件();

??? var s = Directory.GetFiles(folderBrowserDialog1.SelectedPath);

??? 鍵盤操作(l[R.Next(l.Count)], s[R.Next(s.Length)]);

}

?

void 鍵盤操作(HtmlElement 元素, string 填寫文件路徑)

{

??? webBrowser1.Select();

??? webBrowser1.Focus();

??? 元素.Focus();

??? SendKeys.Send("{Tab}");

??? SendKeys.Send(" ");

??? 延遲操作對話框(填寫文件路徑);

}

鼠標模擬方式

還是先看錄制的動畫:

2009-8-5 23-16-51

鼠標模擬的主要流程是:

首先遞歸計算頁面中的文件上傳控件相對于頁面左上角的坐標位置

接著再遞歸計算WebBrowser控件相對于屏幕左上角的位置

在將位置值加上控件自身寬度及高度,并輔以修正值,以確保鼠標能夠點到按鈕上面

移動鼠標到計算好的位置處

單擊鼠標

然后也是延遲3秒等待文件選取對話框顯示,模擬輸入文件路徑并模擬輸入回車鍵

遞歸計算頁面元素相對于頁面坐上角位置的函數:

Point 計算坐標(HtmlElement 元素, Point 起始坐標)

{

??? var p = 起始坐標;

??? p.Offset(元素.OffsetRectangle.Location);

??? return 元素.OffsetParent == null ? p : 計算坐標(元素.OffsetParent, p);

}

遞歸計算控件相對于屏幕左上角位置的函數:

private Point 計算坐標(Control 控件, Point 起始坐標)

{

??? var p = 起始坐標;

??? p.Offset(控件.Location);

??? return 控件.Parent == null ? p : 計算坐標(控件.Parent, p);

}

此外,為了模擬鼠標移動和點擊,還需要引入Windows API:

[DllImport("User32")]

public extern static void SetCursorPos(int x, int y);

?

[DllImport("user32.dll")]

static extern void mouse_event(MouseEventFlag flags, int dx, int dy, uint data, int extraInfo);

?

[Flags]

enum MouseEventFlag : uint

{

??? Move = 0x0001,

??? LeftDown = 0x0002,

??? LeftUp = 0x0004,

??? RightDown = 0x0008,

??? RightUp = 0x0010,

??? MiddleDown = 0x0020,

??? MiddleUp = 0x0040,

??? XDown = 0x0080,

??? XUp = 0x0100,

??? Wheel = 0x0800,

??? VirtualDesk = 0x4000,

??? Absolute = 0x8000

}

主要代碼如下:

private void button2_Click(object sender, EventArgs e)

{

??? var l = 讀取上傳控件();

??? var s = Directory.GetFiles(folderBrowserDialog1.SelectedPath);

??? 鼠標操作(l[R.Next(l.Count)], s[R.Next(s.Length)]);

}

?

void 鼠標操作(HtmlElement 元素, string 填寫文件路徑)

{

??? var p = 計算坐標(元素, new Point());

??? p = 計算坐標(webBrowser1, p);

??? p.Offset(元素.OffsetRectangle.Width - 5, 元素.OffsetRectangle.Height + 15);

??? SetCursorPos(p.X, p.Y);

??? mouse_event(MouseEventFlag.LeftDown | MouseEventFlag.LeftUp, 0, 0, 0, 0);

??? 延遲操作對話框(填寫文件路徑);

}

總結

兩種方法中推薦使用鍵盤模擬方法,簡單而直接;鼠標模擬方法需要使用到API,還需要精確計算,并且如果頁面帶有滾動條,且滾動條進行了滾動或文件上傳控件處于可視區之外的話,將無法通過上述方法計算和操控,而其優點僅僅是直觀一些而已。

?

下載本文的示例源代碼:http://www.uushare.com/user/icesee/file/1869210

下載本文的XPS版本:http://www.uushare.com/user/icesee/file/1869213

轉載于:https://www.cnblogs.com/SkyD/archive/2009/08/06/1540021.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379582.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379582.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379582.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

編寫最簡單的字符設備驅動

編寫最簡單的字符設備驅動1 編寫驅動代碼2 編寫makefile3 編譯和加載驅動4 編寫應用程序測試驅動參考文章&#xff1a; linux驅動開發第1講&#xff1a;帶你編寫一個最簡單的字符設備驅動 linux驅動開發第2講&#xff1a;應用層的write如何調用到驅動中的write 1 編寫驅動代碼…

Java ObjectStreamField toString()方法與示例

ObjectStreamField類toString()方法 (ObjectStreamField Class toString() method) toString() method is available in java.io package. toString()方法在java.io包中可用。 toString() method is used to return a string that defines this field. toString()方法用于返回定…

linux內核文件描述符fd、文件索引節點inode、文件對象file關系

文件描述符fd、文件索引節點inode、文件對象file關系1 VFS對象1.1 超級塊對象1.2 索引節點對象1.3 文件對象1.4 進程描述符1.5 files_struct2 如何根據文件描述符fd找到文件&#xff1f;1 VFS對象 在說fd、inode和file關系之前&#xff0c;我們先了解VFS的幾個概念。分別是進程…

sql2005 獲取表字段信息和視圖字段信息

獲取表字段名,和字段說明SELECT[Table Name]OBJECT_NAME(c.object_id), [ColumnName]c.name, [Description]ex.value FROMsys.columns c LEFTOUTERJOINsys.exte…

解析css之position

CSS的很多其他屬性大多容易理解&#xff0c;比如字體&#xff0c;文本&#xff0c;背景等。有些CSS書籍也會對這些簡單的屬性進行大張旗鼓的介紹&#xff0c;而偏偏忽略了對一些難纏的屬性講解&#xff0c;有避重就輕的嫌疑。CSS中主要難以理解的屬性包括盒型結構&#xff0c;以…

Java ObjectInputStream readLong()方法(帶示例)

ObjectInputStream類readLong()方法 (ObjectInputStream Class readLong() method) readLong() method is available in java.io package. readLong()方法在java.io包中可用。 readLong() method is used to read 8 bytes (i.e. 64 bit) of long value from this ObjectInputSt…

交換瓶子(藍橋杯)

有N個瓶子&#xff0c;編號 1 ~ N&#xff0c;放在架子上。 比如有5個瓶子&#xff1a; 2 1 3 5 4 要求每次拿起2個瓶子&#xff0c;交換它們的位置。 經過若干次后&#xff0c;使得瓶子的序號為&#xff1a; 1 2 3 4 5 對于這么簡單的情況&#xff0c;顯然&#xff0c;至少…

Linux設備驅動開發---字符設備驅動程序

字符設備驅動程序1 主設備和次設備的概念設備號的注冊和釋放靜態方法動態方法區別2 設備文件操作struct file_operations與struct file、struct inode關系3 分配和注冊字符設備class_createcdev_adddevice_create4 字符設備驅動程序字符設備通過字符&#xff08;一個接一個的字…

Java LinkedHashMap getOrDefault()方法與示例

LinkedHashMap類的getOrDefault()方法 (LinkedHashMap Class getOrDefault() method) getOrDefault() method is available in java.util package. getOrDefault()方法在java.util包中可用。 getOrDefault() method is used to get the value associated with the given key el…

Java中的異常棧軌跡和異常鏈

Java中允許對異常進行再次拋出&#xff0c;以提交給上一層進行處理&#xff0c;最為明顯的例子為Java的常規異常。 常規異常&#xff1a;有Java所定義的異常&#xff0c;不需要異常聲明&#xff0c;在未被try-catch的情況下&#xff0c;會被默認上報到main()方法。 Example: pu…

貪心算法---背包問題(物品可以分割問題)

問題背景&#xff1a; 有一天&#xff0c;阿里巴巴趕著一頭毛驢上山砍柴。砍好柴準備下山時&#xff0c;遠處突然出現一股煙塵&#xff0c;彌漫著直向上空飛揚&#xff0c;朝他這兒卷過來&#xff0c;而且越來越近。靠近以后&#xff0c;他才看清原來是一支馬隊&#xff0c;他…

同步---信號量

信號量1 信號量2 驅動程序和測試程序3 內核的具體實現總結1 信號量 Linux中的信號量是一種睡眠鎖。如果有一個任務試圖獲得一個已經被占用的信號量時&#xff0c;信號量會將其放到一個等待隊列&#xff0c;然后讓其睡眠&#xff0c;這時處理器去執行其他代碼。當持有信號量的進…

Java Float類floatToIntBits()方法與示例

Float類floatToIntBits()方法 (Float class floatToIntBits() method) floatToIntBits() method is available in java.lang package. floatToIntBits()方法在java.lang包中可用。 floatToIntBits() method follows IEEE 754 floating-point standards and according to standa…

解釋三度帶和六度帶的概念以及各坐標系如何定義

★ 地形圖坐標系&#xff1a;我國的地形圖采用高斯&#xff0d;克呂格平面直角坐標系。在該坐標系中&#xff0c;橫軸&#xff1a;赤道&#xff0c;用&#xff39;表示&#xff1b;縱軸&#xff1a;中央經線&#xff0c;用&#xff38;表示&#xff1b;坐標原點&#xff1a;中央…

0-1背包問題(物品不可分割)

問題背景&#xff1a; 所謂“鐘點秘書”&#xff0c;是指年輕白領女性利用工余時間為客戶提供秘書服務&#xff0c;并按鐘點收取酬金。“鐘點秘書”為客戶提供有償服務的方式一般是&#xff1a;采用電話、電傳、上網等“遙控”式 服務&#xff0c;或親自到客戶公司處理部分業務…

算法---KMP算法

字符串1 KMP算法狀態機概述構建狀態轉移1 KMP算法 原文鏈接&#xff1a;https://zhuanlan.zhihu.com/p/83334559 先約定&#xff0c;本文用pat表示模式串&#xff0c;長度為M&#xff0c;txt表示文本串&#xff0c;長度為N&#xff0c;KMP算法是在txt中查找子串pat&#xff0…

cache初接觸,并利用了DataView

我們在寫代碼的時候,如果數據控件要獲得數據,一般方法,Conn.Open();OleDbCommand cmd;cmd new OleDbCommand(sql, Conn);GridView1.DataSource dbcenter.accessGetDataSet(sql);GridView1.DataBind();Conn.close();但如果多個數據控件要綁定數據,則比較頻繁打開數據庫,效率一…

Java ByteArrayInputStream reset()方法及示例

ByteArrayInputStream類reset()方法 (ByteArrayInputStream Class reset() method) reset() method is available in java.util package. reset()方法在java.util包中可用。 reset() method is used to reset this ByteArrayInputStream to the last time marked position and …

回文數猜想

問題描述&#xff1a; 一個正整數&#xff0c;如果從左向右讀&#xff08;稱之為正序數&#xff09;和從右向左讀&#xff08;稱之為倒序數&#xff09;是一樣的&#xff0c;這樣的數就叫回文數。任取一個正整數&#xff0c;如果不是回文數&#xff0c;將該數與他的倒序數相加…

文件上傳 帶進度條(多種風格)

文件上傳 帶進度條 多種風格 非常漂亮&#xff01; 友好的提示 以及上傳驗證&#xff01; 部分代碼&#xff1a; <form id"form1" runat"server"><asp:ScriptManager ID"scriptManager" runat"server" EnablePageMethods&quo…