zoukankan      html  css  js  c++  java
  • 在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://www.uushare.com/user/icesee/file/1869210

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

  • 相关阅读:
    Nested Lists比较经典的python代码
    Matching Character Ranges
    python 刷题记录
    SQL Access Advisor and SQL Tunning Advisor
    Reactor IO模型
    聊聊page cache与Kafka之间的事儿
    node.js cmd 输入npm-v无反应
    鼠标突然无反应,鼠标灯亮,鼠标灯不亮
    js图片转换为base64
    js实现倒计时60秒的简单代码
  • 原文地址:https://www.cnblogs.com/mvc2014/p/3775956.html
Copyright © 2011-2022 走看看