大多数C#程序员对于使用HttpRequest、HttpResponse、WebClient这样的类向Web服务器发出请求并取得响应结果并不陌生。
但有时我们想模拟用户操纵浏览器的场景(尤其是在自动化测试时),那么我们可以选择使用mshtml.dll和shdocvw.dll来完成对IE DOM的操作以实现此功能。
假设我们想访问http://community.csdn.net/,并在这之前已经登录,那么实际上我们应该访问http://passport.csdn.net/UserLogin.aspx?from=http://community.csdn.net/,并在此页面输入用户名、密码、验证码并点击登录按钮。
首先我们新建一个Console项目,并添加对mshtml.dll(添加引用--.NET选项卡--Microsoft.mshtml)和shdocvw.dll(添加引用--COM选项卡--Microsoft Internet Controls)的引用。
详细内容请参考代码注释
- using System;
- using System.Diagnostics;
- using System.Threading;
- using mshtml;
- using SHDocVw;
- namespace IEDemo
- {
- class Program
- {
- static AutoResetEvent documentComplete = new AutoResetEvent(false);
- static void Main(string[] args)
- {
- Console.WriteLine(DateTime.Now.ToString() + " 开始");
- InternetExplorer ie = GetInternetExplorer();
- if (ie != null)
- {
- Run(ie);
- }
- Console.WriteLine(DateTime.Now.ToString() + " 结束");
- }
- private static InternetExplorer GetInternetExplorer()
- {
- InternetExplorer ie = null;
- Console.WriteLine(DateTime.Now.ToString() + " 加载IE实例");
- //查找是否有打开的IE进程窗口,如果已经包含CSDN登录页,则得到此进程
- Process[] processes = Process.GetProcesses();
- Process process = null;
- foreach (Process p in processes)
- {
- if (string.Compare(p.ProcessName, "iexplore", true) == 0)
- {
- if (p.MainWindowTitle.IndexOf("CSDN 用户登录") >= 0) // CSDN 用户登录 - Windows Internet Explorer
- {
- process = p;
- break;
- }
- }
- }
- //如果没有则启动IE实例
- if (process == null)
- {
- process = Process.Start("iexplore.exe", "about:blank");
- }
- if (process == null)
- {
- Console.WriteLine(DateTime.Now.ToString() + " 无法启动IE");
- return null;
- }
- Thread.Sleep(3000);
- try
- {
- Console.WriteLine(DateTime.Now.ToString() + " Process Handle: " + process.MainWindowHandle.ToString());
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- return null;
- }
- ShellWindows browsers = new ShellWindows();
- Console.WriteLine(DateTime.Now.ToString() + " 活动浏览器数量: " + browsers.Count);
- if (browsers.Count == 0)
- {
- Console.WriteLine(DateTime.Now.ToString() + " 未找到IE");
- }
- //如果找到匹配的IE进程,则把当前InternetExplorer对象连接到正在运行的IE程序
- Console.WriteLine(DateTime.Now.ToString() + " 附加到IE");
- int i = 0;
- while (i < browsers.Count && ie == null)
- {
- InternetExplorer e = browsers.Item(i) as InternetExplorer;
- if (e != null)
- {
- if (e.HWND == (int)process.MainWindowHandle)
- {
- ie = e;
- break;
- }
- }
- ++i;
- }
- if (ie == null)
- {
- Console.WriteLine(DateTime.Now.ToString() + " 附加到IE失败");
- }
- return ie;
- }
- private static void Run(InternetExplorer ie)
- {
- ie.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(ie_DocumentComplete);
- try
- {
- HTMLDocument document = null;
- object o = new object();
- //导航到CSDN登录页
- ie.Navigate("http://passport.csdn.net/UserLogin.aspx?from=http://community.csdn.net/", ref o, ref o, ref o, ref o);
- documentComplete.WaitOne(1000, true);
- document = ie.Document as HTMLDocument;
- if (document != null)
- {
- //以下操纵IE Shell
- HTMLInputButtonElement name = document.getElementById("ctl00_CPH_Content_tb_LoginNameOrLoginEmail") as HTMLInputButtonElement;
- if (name != null)
- {
- //csdn用户名
- name.value = "yourcsdnusername";
- }
- HTMLInputButtonElement password = document.getElementById("ctl00_CPH_Content_tb_Password") as HTMLInputButtonElement;
- if (password != null)
- {
- //csdn密码
- password.value = "yourcsdnpassword";
- }
- HTMLInputButtonElement imagecode = document.getElementById("ctl00_CPH_Content_tb_ExPwd") as HTMLInputButtonElement;
- if (imagecode != null)
- {
- Console.Write("输入验证码:");
- //控制台窗口输入验证码
- string code = Console.ReadLine();
- imagecode.value = code;
- }
- HTMLInputButtonElement submit = document.getElementById("ctl00_CPH_Content_Image_Login") as HTMLInputButtonElement;
- if (submit != null)
- {
- submit.click();
- documentComplete.WaitOne(1000, true);
- }
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- // ie.Quit();
- }
- private static void ie_DocumentComplete(object pDisp, ref object URL)
- {
- documentComplete.Set();
- }
- }
- }