这里说说怎么根据用户设置的图书馆账号和密码去自动登录图书馆网站,并提取出读者的借阅信息发送到提示框或保存到本地XML文件中,创建工程HttpService,添加对DALService,IDoWork,Model,Windows.Forms的引用。
与远程web站点交互有多种方法,像WebClient和HttpWebRequest等都可以,但是本人在使用这些方法时能得到页面信息,但是自动登录不成功,最后采用.Net提供的WebBrowser控件,这个实现再来很容易,而且得到的数据很容易处理,这里采用的是DOM解析,但是也有一个缺点是读取数据依赖于该控件的DocumentCompleted事件,也就是文件全部加载完后才执行,并且是程序进入Run等待状态时才执行的最后一个函数,所以用这种方法整个系统对它的依赖都很大,不像用其它方法发送请求就得到结果这么简单。
WebBrowser的使用很简单,只要指定它的URL它就自动跳转到该页面,接着再注册它的DocumentCompleted事件,再该事件里就可以DOM解析该页面上的每一个Html元素,就像平时写JavaScript一样简单,例如要自动登录就要得到用于填写用户名和密码的文本框和提交登录的按钮就可以这样实现:
//取得提交按钮,
ImageButton1为图书馆网站上用于提交的按钮的ID,下面的一样
HtmlElement btnSubmit = webBrowser.Document.GetElementById("ImageButton1");
//取得用于填写用户名的文本框
HtmlElement txtUserName = webBrowser.Document.GetElementById("TextBox1");
HtmlElement txtUserPassword = webBrowser.Document.GetElementById("TextBox2");
再往两个文本框里赋值:
txtUserName.SetAttribute("value", user.LoginID);
txtUserPassword.SetAttribute("value", user.Password);
再实现提交:
btnSubmit.InvokeMember("click");
提交完后不用做处理,远程服务器执行完后自动将结果返回给WebBrowser,这时又再执行一次DocumentCompleted事件。
下面来说说一下本系统是怎么实现的,首先从设计中可以看出它与图书馆网站交互,读取出数据,在自动登录时是把数据发到提示框中,在手动登录时是把数据去更新用户的编辑界面,两种登录都把数据保存到本地XML文件,所以我们提供一个抽象类AbsHttp,它去实现把IDoWork接口,DoWork里面具体做的工程是把数据保存到本地XML文件,再提供一个虚方法,让它的子类去重写,有两个子类去实现,一个是用于自动登录的,它实现时就把数据发到提示框,另一个是用于手动登录情况的,它实现时就把数据去更新用户的编辑界面。
如下,定义一个WebBrowser控件与网络交互
private WebBrowser webBrowser = new WebBrowser();
定义一个保存图书的集合用来发送到各个地方
protected List<Book> bookList = new List<Book>();
再定义一个User对象用于去自动登录
private User user;
在实现IDoWork接口中的DoWork方法时我们要做的就是去取得用户账号和让WebBrowser去工作,如下:
public Boolean DoWork()
{
GetUser();
webBrowser.ScriptErrorsSuppressed = true; //页面有脚本错误就跳过
webBrowser.Url = new System.Uri(@"http://210.46.107.20/gdweb/ReaderLogin.aspx", System.UriKind.Absolute);
webBrowser.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.webBrowser_DocumentCompleted);
return true; //该方法返回是否启动应用程序的Run方法,当网络连接正常时从网络上读数据时必须进入Run方法才能执行WebBrowser的DocumentCompleted事件
}
但要注意的是这里要返回true,提供的Url是图书馆登录界面的Url,下面看看DocumentCompleted是怎么实现的:
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using LibraryHelper.IDoWork;
using LibraryHelper.Model;
using LibraryHelper.DALService;
namespace LibraryHelper.HttpService
{
public abstract class AbsHttp : ILibraryHelperDoWork
{
private WebBrowser webBrowser = new WebBrowser();
protected List<Book> bookList = new List<Book>();
private User user;
public Boolean DoWork()
{
GetUser();
webBrowser.ScriptErrorsSuppressed = true; //页面有脚本错误就跳过
webBrowser.Url = new System.Uri(@"http://210.46.107.20/gdweb/ReaderLogin.aspx", System.UriKind.Absolute);
webBrowser.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.webBrowser_DocumentCompleted);
return true; //该方法返回是否启动应用程序的Run方法,当网络连接正常时从网络上读数据时必须进入Run方法才能执行WebBrowser的DocumentCompleted事件
}
private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//提交表单前来执行一次这个事件,提交后又执行一次
//提交后URL改变了,所以用这个特点来判断是哪一次
if (webBrowser.Url.ToString() == @"http://210.46.107.20/gdweb/ReaderLogin.aspx")
{
try
{
HtmlElement btnSubmit = webBrowser.Document.GetElementById("ImageButton1");
HtmlElement txtUserName = webBrowser.Document.GetElementById("TextBox1");
HtmlElement txtUserPassword = webBrowser.Document.GetElementById("TextBox2");
if (txtUserName == null || txtUserPassword == null || btnSubmit == null)
return;
if (user.LoginID == "" || user.Password == "")
return;
txtUserName.SetAttribute("value", user.LoginID);
txtUserPassword.SetAttribute("value", user.Password);
btnSubmit.InvokeMember("click");
}
catch (Exception ex)
{
throw ex;
}
}
if (webBrowser.Url.ToString() == @"http://210.46.107.20/gdweb/ReaderTable.aspx")
{
//网络上读取下来的文件
HtmlElement htmlElement = webBrowser.Document.GetElementById("DataGrid1").Children[0];
//记取出来的记录数量
Int32 bookNum = htmlElement.Children.Count;
for (Int32 i = 1; i < bookNum; i++)
{
Book book = new Book();
book.Title = htmlElement.Children[i].Children[1].InnerText;
book.BorrowDate = Convert.ToDateTime(htmlElement.Children[i].Children[2].InnerText);
book.ReturnDate = Convert.ToDateTime(htmlElement.Children[i].Children[3].InnerText);
book.BorrowNum = htmlElement.Children[i].Children[4].InnerText;
book.ISBN = htmlElement.Children[i].Children[5].InnerText;
bookList.Add(book);
}
//保存到本地
SaveBookList();
//提供一个虚方法让子类去重写,有可能是发送到提示框,也可能是去更新用户的编辑窗体
SendBookList();
}
}
//保存到本地
private void SaveBookList()
{
BookXMLService bookXMLService = new BookXMLService();
bookXMLService.SaveBookList(bookList);
}
//提供一个虚方法让子类去重写,有可能是发送到提示框,也可能是去更新用户的编辑窗体
protected virtual void SendBookList()
{
}
//取得用户帐号信息
private void GetUser()
{
UserXMLService userXMLService = new UserXMLService();
user = userXMLService.GetUser();
}
}
}
这里面由于提交登录信息后服务器的Url改变了,所以我们用一个判断语句来判断执行不同的工作,还有这一句
//网络上读取下来的文件
HtmlElement htmlElement = webBrowser.Document.GetElementById("DataGrid1").Children[0];
先来看看从服务器上读取返回的页面结果:
Code
<table border="1" cellpadding="0" cellspacing="0" bordercolor="#0099cc" style="width: 766px">
<tr>
<td valign="top" style="width: 678px; height: 157px;">
<span id="LblyjMessage"></span>
<table cellspacing="0" cellpadding="4" rules="rows" border="1" id="DataGrid1" style="color:Black;background-color:White;border-color:#CCCCCC;border-width:1px;border-style:None;width:112%;border-collapse:collapse;">
<tr style="color:White;background-color:SteelBlue;font-weight:bold;">
<td style="color:White;">条形码</td><td style="color:White;">题名</td><td style="color:White;">外借时间</td><td style="color:White;">应还时间</td><td style="color:White;">续借次数</td><td style="color:White;">索书号</td><td>馆藏地点</td>
</tr><tr>
<td>0817343</td><td>重构:改善既有代码的设计</td><td>2008-12-21</td><td>2009-03-23</td><td>
0
<a href='CheckBespeak.aspx?BookID=313643&BookCode=0817343'>
续借</a>
</td><td>TP311.11/31</td><td>科技借阅室</td>
</tr><tr>
<td>0986967</td><td>企业应用架构模式</td><td>2008-12-29</td><td>2009-03-23</td><td>
0
<a href='CheckBespeak.aspx?BookID=438508&BookCode=0986967'>
续借</a>
</td><td>F270.7/138</td><td>社科五借阅室</td>
</tr><tr>
<td>1980580</td><td>数据结构教程</td><td>2009-03-11</td><td>2009-04-11</td><td>
0
<a href='CheckBespeak.aspx?BookID=641614&BookCode=1980580'>
续借</a>
</td><td>TP311.12/121-2</td><td>科技借阅室</td>
</tr><tr>
<td>1762287</td><td>数据结构习题与解析</td><td>2009-03-11</td><td>2009-04-11</td><td>
0
<a href='CheckBespeak.aspx?BookID=445000&BookCode=1762287'>
续借</a>
</td><td>TP311.12/16-2</td><td>科技借阅室</td>
</tr><tr>
<td>1545784</td><td>JAVA面向对象程序设计</td><td>2009-03-11</td><td>2009-04-11</td><td>
0
<a href='CheckBespeak.aspx?BookID=295330&BookCode=1545784'>
续借</a>
</td><td>TP312JA/217</td><td>科技借阅室</td>
</tr><tr>
<td>1647653</td><td>HEAD FIRST设计模式:中文版</td><td>2008-12-21</td><td>2009-03-23</td><td>
0
<a href='CheckBespeak.aspx?BookID=639472&BookCode=1647653'>
续借</a>
</td><td>TP312JA/368</td><td>科技借阅室</td>
</tr><tr>
<td>1878912</td><td>EXPERT C# 2005 BUSINESS OBJECTS中文版</td><td>2008-12-21</td><td>2009-04-06</td><td>
1
<a href='CheckBespeak.aspx?BookID=429860&BookCode=1878912'>
续借</a>
</td><td>TP312C/619</td><td>科技借阅室</td>
</tr>
</table></td>
</tr>
</table>
</td>
</tr>
</table>
注意看上面图书结果中有一个表格的IDDataGrid1,用DOM一下子就找到我们想要的信息,很简单方便。
全部实现的代码如下:AbsHttp.cs
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using LibraryHelper.IDoWork;
using LibraryHelper.Model;
using LibraryHelper.DALService;
namespace LibraryHelper.HttpService
{
public abstract class AbsHttp : ILibraryHelperDoWork
{
private WebBrowser webBrowser = new WebBrowser();
protected List<Book> bookList = new List<Book>();
private User user;
public Boolean DoWork()
{
GetUser();
webBrowser.ScriptErrorsSuppressed = true; //页面有脚本错误就跳过
webBrowser.Url = new System.Uri(@"http://210.46.107.20/gdweb/ReaderLogin.aspx", System.UriKind.Absolute);
webBrowser.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.webBrowser_DocumentCompleted);
return true; //该方法返回是否启动应用程序的Run方法,当网络连接正常时从网络上读数据时必须进入Run方法才能执行WebBrowser的DocumentCompleted事件
}
private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//提交表单前来执行一次这个事件,提交后又执行一次
//提交后URL改变了,所以用这个特点来判断是哪一次
if (webBrowser.Url.ToString() == @"http://210.46.107.20/gdweb/ReaderLogin.aspx")
{
try
{
HtmlElement btnSubmit = webBrowser.Document.GetElementById("ImageButton1");
HtmlElement txtUserName = webBrowser.Document.GetElementById("TextBox1");
HtmlElement txtUserPassword = webBrowser.Document.GetElementById("TextBox2");
if (txtUserName == null || txtUserPassword == null || btnSubmit == null)
return;
if (user == null)
return;
txtUserName.SetAttribute("value", user.LoginID);
txtUserPassword.SetAttribute("value", user.Password);
btnSubmit.InvokeMember("click");
}
catch (Exception ex)
{
throw ex;
}
}
if (webBrowser.Url.ToString() == @"http://210.46.107.20/gdweb/ReaderTable.aspx")
{
//网络上读取下来的文件
HtmlElement htmlElement = webBrowser.Document.GetElementById("DataGrid1").Children[0];
//记取出来的记录数量
Int32 bookNum = htmlElement.Children.Count;
for (Int32 i = 1; i < bookNum; i++)
{
Book book = new Book();
book.Title = htmlElement.Children[i].Children[1].InnerText;
book.BorrowDate = Convert.ToDateTime(htmlElement.Children[i].Children[2].InnerText);
book.ReturnDate = Convert.ToDateTime(htmlElement.Children[i].Children[3].InnerText);
book.BorrowNum = htmlElement.Children[i].Children[4].InnerText;
book.ISBN = htmlElement.Children[i].Children[5].InnerText;
bookList.Add(book);
}
//保存到本地
SaveBookList();
//提供一个虚方法让子类去重写,有可能是发送到提示框,也可能是去更新用户的编辑窗体
SendBookList();
}
}
//保存到本地
private void SaveBookList()
{
BookXMLService bookXMLService = new BookXMLService();
bookXMLService.SaveBookList(bookList);
}
//提供一个虚方法让子类去重写,有可能是发送到提示框,也可能是去更新用户的编辑窗体
protected virtual void SendBookList()
{
}
//取得用户帐号信息
private void GetUser()
{
UserXMLService userXMLService = new UserXMLService();
user = userXMLService.GetUser();
}
}
}