一个开心网记录发布小程序的原理
开心网提供一个功能叫做“记录”,类似博客园的闪存,如果要使用它总是需要打开浏览器,登录开心网,然后通过数次鼠标操作才可以发出一条记录。那能否做一个小程序,在程序中输入记录内容,直接发送出去呢?虽然开心网并没有提供API,但是我们完全可以通过在浏览器中模拟手工操作来做到这一点。
通过手工操作来观察和分析这个功能的行为,发现我们可以直接输入记录这个功能的URL地址,登录之后就可以直接发记录了,记录的页面很简单,一个文本框加一个按钮。我们只需要操作浏览器控件,导航到记录的URL,然后获取记录页面的文本框和按钮,在文本框中加入文本,然后模拟点击按钮,就可以发记录了。下面我们就利用.NET Framework提供的WebBrowser控件实际来操作一下。
在我的程序的窗体中,有一个文本框tbContent、一个按钮btnRecord,还有一个WebBrowser类型的私有变量(注意仅仅是一个变量,而不是拖到设计界面中的控件)。然后可以在tbContent中输入内容,单击btnRecord就可以发送记录了。
一切始于btnRecord的单击事件处理方法:
{
//因为我们不需要将浏览器显示在界面上,因此只需要后台动态创建,“隐蔽”操作就好
browser = new WebBrowser();
//将浏览器的文档加载完成事件关联到一个事件处理方法上,
//因为我们的操作需要在文档加载完成之后才可以操作。
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browser_DocumentCompleted);
browser.Navigate("http://www.kaixin001.com/app/app.php?aid=1018"); //导航到记录页面
}
当导航到记录页面时,因为我们并未登录,因此必然会被重定向到登录页面,然后我们录入用户名和密码并单击按钮提交之后,就会被重新导向记录页面,不管我们是录入登录信息,还是录入记录信息,都必须要等到浏览器中的文档加载完毕之后才能操作,因此这2个操作都是在浏览器控件的DocumentCompleted事件处理方法中处理的。问题是怎么在事件处理方法中区分当前是录入登录信息还是记录信息呢?一个简单的方法是,判断文档的标题,如果存在“登录”字样,则录入登录信息,如果存在“记录”字样则录入记录信息。以下是DocumentCompleted事件处理方法的代码:
{
HtmlDocument doc = browser.Document; //获取加载完成的页面文档
if (doc.Title.Contains("登录")) //判断文档标题是否包含“登录”字样
LoginKaiXin(doc); //执行登录操作
if (doc.Title.Contains("记录")) //判断文档标题是否包含“记录”字样
ExecuteRecord(doc); //执行记录操作
}
接下来,我们看看LoginKaiXin方法的代码,其中我们需要做的事情就是获取用户名和密码文本框并填充入需要的字符串,最后单击登录按钮:
{
HtmlElement email, password, btnLogin; //登录页面我们关心的三个元素
//分别获取2个录入元素
email = doc.All["email"];
password = doc.All["password"];
//为其赋值
email.SetAttribute("value", "开心网帐号");
password.SetAttribute("value", "开心网密码");
//获取登录按钮并单击
btnLogin = doc.All["btn_dl"];
btnLogin.InvokeMember("click");
}
其中各个控件的ID值,我们可以通过手工操作,然后查看浏览器中页面的HTML源代码找到。当登录按钮被单击之后,浏览器会提交信息,如果验证成功,则会重定向到记录页面,记录页面文档加载完成之后,浏览器控件又会引发DocumentCompleted事件,从而根据逻辑会执行ExecuteRecord方法,与LoginKaiXin的代码类似,其代码如下:
{
HtmlElement word, btnSubmit;
//这里出于演示目的换了一种方法获取页面控件引用
word = doc.GetElementById("word");
word.SetAttribute("value", tbContent.Text);
btnSubmit = doc.GetElementById("btn_fb");
btnSubmit.InvokeMember("click");
browser.Dispose(); //执行完成之后,释放浏览器占用的资源
}
一切搞定。简单吧。注意贴出来代码中,把一些界面上的辅助性代码(比如“正在发送”、“发送成功”之类的提示性信息操作代码)都删除了,只保留与浏览器控件操作有关的代码。