在WebBrowser中通过模拟键盘鼠标操控网页中的文件上传控件(转)
引言
这两天沉迷了Google SketchUp,刚刚玩够,一时兴起,研究了一下WebBrowser。
我在《WebBrowser控件使用技巧分享》一文中曾谈到过“我现在可以通过WebBrowser实现对各种Html元素的操控,唯独无法控制Html的上传控件”,出于安全原因,IE没有对上传控件提供操控支持,这使得我们没法像控制其他控件一样用简单的代码进行赋值。
比较实际的解决方案就是模拟操作了,下面我就将演示通过键盘、鼠标两种方式模拟点击“浏览”按钮,然后配合键盘模拟输入文件路径,并按回车键确认。
初始环境
测试使用了一个简单的HTML页面,页中各个位置中分布了一些文件上传控件,有些是直接放置的,有些是横向排列的,有些是嵌套在表格中的,用以测试不同位置的触发效果:
将此页面用WebBrowser控件加载。
在程序界面中,我放置了一些控件用于选择上传文件所在目录,测试时首先选定一个包含有文件的目录,然后从中随机抽选一个文件填写到上传控件中:
并在代码中建立了一个辅助方法,用以读取页面上所有的文件上传控件,在测试时也是从中随机抽取一个进行操控:
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秒,延迟结束后在回调事件中进行操作。
键盘模拟方式
先看录制的动画:
在这里首先选择了一个上传文件所在目录,然后进行了几次键盘模拟操作测试。
键盘模拟的操作流程如下:
首先激活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(" ");
延迟操作对话框(填写文件路径);
}
鼠标模拟方式
还是先看录制的动画:
鼠标模拟的主要流程是:
首先递归计算页面中的文件上传控件相对于页面左上角的坐标位置
接着再递归计算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://skyd.cnblogs.com/
在WebBrowser中通过模拟键盘鼠标操控网页中的文件上传控件(转)的更多相关文章
- ASP.NET中的FileUpload文件上传控件的使用
本篇文章教大家如何将客户端的图片或者文件上传到服务器: 无论是上传图片(.jpg .png .gif等等) 文档(word excel ppt 等等). 第一步:放入以下三个控件 Image控件,Fi ...
- js_ajax模拟form表单提交_多文件上传_支持单个删除
需求场景: 用一个input type="file"按钮上传多张图片,可多次上传,可单独删除,最后使用ajax模拟form表单提交功能提交到指定方法中: 问题:由于只有一个file ...
- NeatUpload上传控件在asp.net中的使用
1.先导包,Brettle.Web.NeatUpload.dll导进web层中,再添加到vs控件中. 2.把NeatUpload文件夹放到根目录下. 3.直接拉要用到的控件到页面上,在使用 <U ...
- vue+ElementUI项目中,上传控件为必填项,上传图片后清空提示信息
(ps:以下是我在项目中遇到得问题及解决方法,希望对你们有帮助.如果还有其他方法,可以留言,谢谢) 一个表单页面,使用element-ui中el-upload上传图片,此项为必填项,然后写了校验规则, ...
- jquery中选择ID以什么字符开头的匹配主要用于多个上传控件的时候,id无法使用,而且class不起作用的时候
$("[id^=remark]")选择ID以remark开头的所有数据进行匹配
- Eclipse中使用GIT将已提交到本地的文件上传至远程仓库
GIT将已提交到本地的文件上传至远程仓库: 1. 右击项目——Team——Push to Upstream,即可将已保存在本地的文件上传推至GIT远程仓库.
- JQuery文件上传插件ajaxFileUpload在Asp.net MVC中的使用
0 ajaxFileUpload简介 ajaxFileUpload插件是一个非常简单的基于Jquery的异步上传文件的插件,使用过程中发现很多与这个同名的,基于原始版本基础之上修改过的插件,文件版本比 ...
- 转:在Struts 2中实现文件上传
(本文转自:http://www.blogjava.net/max/archive/2007/03/21/105124.html) 前一阵子有些朋友在电子邮件中问关于Struts 2实现文件上传的问题 ...
- 转:MVC中的文件上传
上传文件与与上传数据区别 上传数据主要指json等简单字符串,上传文件指的是上传word.excel图片等.在上传数据的时候enctype默认为第一个application/x-www-form-ur ...
随机推荐
- Effective C++ -----条款12: 复制对象时勿忘其每一个成分
Copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”. 不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两个cop ...
- linux 解压缩
tar f 使用档案名字,这个参数是最后一个参数,后面只能接档案名 c 建立压缩档案 x 解压 t 查看内容 r 向压缩归档文件末尾追加文件 u 更新原压缩包中的文件 z 有gzip属性的 j 有bz ...
- stm32——NFC芯片--PN532的使用
stm32——NFC芯片--PN532的使用 一.NFC简介 NFC(Near Field Communication)近场通信,是一种短距高频的无线电技术,在13.56MHz频率运行于20厘米距离内 ...
- python基础——错误处理
python基础——错误处理 在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因.在操作系统提供的调用中,返回错误码非常常见.比如打开文件的函数 ...
- 解决Fragment在Viepager中切换不保存状态的问题
在FragmentPagerAdapter中重写以下方法: @Override public Object instantiateItem(ViewGroup container, int posit ...
- wireshark_Couldn’t run /usr/sbin/dumpcap in child process: Permission denied
关于Wireshark出现:Couldn't run /usr/sbin/dumpcap in child process: Permission denied Are you a member of ...
- Smarty模板技术学习(二)
本文主要包括以下内容 公共文件引入与继承 内容捕捉 变量调剂器 缓存 Smarty过滤器 数据对象.注册对象 与已有项目结合 公共文件引入与继承 可以把许多模板页面都用到的公共页面放到单独文件里边,通 ...
- DLog的使用
DLog本质上就是个宏替换.DLog具体代码如下: #ifdef DEBUG #define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt) ...
- WMI测试
https://social.msdn.microsoft.com/Forums/windowshardware/zh-CN/c5af7959-95d3-4e1b-ab40-96a2a31c2af2/ ...
- 无废话Android之activity的生命周期、activity的启动模式、activity横竖屏切换的生命周期、开启新的activity获取他的返回值、利用广播实现ip拨号、短信接收广播、短信监听器(6)
1.activity的生命周期 这七个方法定义了Activity的完整生命周期.实现这些方法可以帮助我们监视其中的三个嵌套生命周期循环: (1)Activity的完整生命周期 自第一次调用onCrea ...