网站复杂信息自动录入处理
问题:某某系统是基于B/S的,无法获得数据接口,有信息录入页面,该信息录入页面是基于showModalDialog的,且录入完初步信息后会redirect到另一URL(假设原URL为URL1,重定向后URL为URL2),其他的信息在URL2中要通过javascript切换链接(像TAB页效果一样)才能继续录入,录入过程中有可能提交后有alert信息提示,现有待数据一堆(1000条),要求实现数据的程序自动化录入。
解决方案:使用ExtendedWebBrowser处理,用WebBrowser打开URL1,取得HTML文档后自动填写表单,然后调用提交函数,待转向URL2后,再调用Javascript函数转向其他信息录入页面,并自动填写表单,调用保存JS函数,一条记录的所有信息录入完成后,转向URL1,重新开始,录入下一条数据。
几个技术点:
1.目标系统中showModalDialog出来的页面无状态条,无法知道URL1。
解决:先通过ieHttpHeaders跟踪showModalDialog,取得URL1的实际值。
2.无法得知录入页面是否加载完成。
解决:在DocumentCompleted事件处理程序中判断ReadyState后,加入输出e.url语句,启动自已基于ExtendedWebBrowser开发的浏览器程序,把各步骤中表单可以自动填单后的最后输出的那个URL记录下来,形成各步骤的特征URL,这样就能处理frames和Iframe及JS中加载的页面。如:
void brw_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (_windowManager.ActiveBrowser.ReadyState == WebBrowserReadyState.Complete)
{
SouthHIS.modOutputLog.OutputLog(e.Url.ToString());
}
}
记录下来的有:
步骤1:http://xxx.xxx/BasicInfo.aspx?OpFlag=add&strGuardNo=
步骤2:http://xxx.xxx/aaedit2.aspx
步骤2:http://xxx.xxx/aaedit3.aspx
3.各步骤填写表单有可能出错而要重复执行,如何让各步骤确定地执行完成上一步后再执行下一步并串起来.
解决:使用状态机方案,画好状态机图,然后定义一个变量表示状态机状态,执行成功一个步骤后,改变状态变量以让状态机执行下一动作,如果执行不成功,可以返回重新执行,或是返回上一步再重新加载等。
4.程序执行速度过快,即使程序表明页面载完成,自动填入表单时还是会发生一些页面里的onload时执行的未完成,导致后续填写表单或执行JS出错.即:判断出某步骤“加载完”最后的页面URL,执行填单程序,有时还是会出错,如何处理。
解决:使用多线程,让步骤执行在非主线程上执行,在满足载条件后再等待一段时间,让WebBrowser加载彻底完成后,再使用invoke来执行各步骤的填单程序.
样例程序:
public class InvokeObject
{
public System.Threading.ThreadStart m_func;
public MainForm m_frm;
public InvokeAA(System.Threading.ThreadStart func,MainForm frm)
{
m_func = func;
m_frm = frm;
}
public void ToThreadCall()
{
DateTime dt1 = DateTime.Now;
while (true)//等待“加载完成”后再等待200MS
{
Application.DoEvents();
DateTime dt2 = DateTime.Now;
TimeSpan ts = dt2.Subtract(dt1);
if (ts.Milliseconds > 200)
{
break;
}
}
m_frm.Invoke(m_func);//执行真正的步骤处理函
}
}
使用代码:
InvokeAA abc = new InvokeAA(GoToFamilyPage, this);//GoToFamilyPage是步骤处理函数
System.Threading.Thread th2 = new System.Threading.Thread(abc.ToThreadCall);
th2.Name = "GoToFamilyPage";
th2.Start();
5.如何拦截alert对话框,以让其继续.
解决:扩展WebBrowser,处理 ShowMessage.在extendedWebBrowser中,加入代码:
//拦截alert
#region ExtendedWebBrowserSite
class ExtendedWebBrowserSite : WebBrowser.WebBrowserSite, UnsafeNativeMethods.IDocHostShowUI
{
WebBrowser m_host;
public ExtendedWebBrowserSite(WebBrowser host)
: base(host)
{
m_host = host;
}
void UnsafeNativeMethods.IDocHostShowUI.ShowMessage(ref UnsafeNativeMethods._RemotableHandle hwnd, string lpstrText, string lpstrCaption, uint dwType, string lpstrHelpFile, uint dwHelpContext, out int plResult)
{
//TODO:自定义处理弹出消息框
//dwType:0x00000030问题
SouthHIS.modOutputLog.OutputLog(lpstrText);
SouthHIS.modOutputLog.OutputLog(dwType);
if (dwType != 0x00000030)
{
//plResult = (int)System.Windows.Forms.MessageBox.Show(lpstrText, lpstrCaption, (MessageBoxButtons)dwType );
}
plResult = 1;
}
void UnsafeNativeMethods.IDocHostShowUI.ShowHelp(ref UnsafeNativeMethods._RemotableHandle hwnd, string pszHelpFile, uint uCommand, uint dwData, UnsafeNativeMethods.tagPOINT ptMouse, object pDispatchObjectHit)
{
//TODO:自定义处理弹出帮助消息框
}
}
protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
{
return new ExtendedWebBrowserSite(this);
}
6.如何拦截执行JS出错时弹出的脚本错误对话框
解决:在加载页面前,使用:
brw.ScriptErrorsSuppressed = true;
让其不显示对话框.
7.如何取得frames,如何执行javascript,如何定义额外的javascript函数,如何取得执行javascript函数的返回值。
解决:
HtmlWindow win1 = _windowManager.ActiveBrowser.Document.Window.Frames[0];
mshtml.IHTMLWindow2 win2 = (mshtml.IHTMLWindow2)win1.DomWindow;
try
{
string script11 = "function SaveRow11() { return '0';}";
win2.execScript(script11, "javascript");
string strRetVal = (string)win1.Document.InvokeScript("SaveRow11");
if(strRetVal =='0')
{
....
}
}catch .....
解决方案:使用ExtendedWebBrowser处理,用WebBrowser打开URL1,取得HTML文档后自动填写表单,然后调用提交函数,待转向URL2后,再调用Javascript函数转向其他信息录入页面,并自动填写表单,调用保存JS函数,一条记录的所有信息录入完成后,转向URL1,重新开始,录入下一条数据。
几个技术点:
1.目标系统中showModalDialog出来的页面无状态条,无法知道URL1。
解决:先通过ieHttpHeaders跟踪showModalDialog,取得URL1的实际值。
2.无法得知录入页面是否加载完成。
解决:在DocumentCompleted事件处理程序中判断ReadyState后,加入输出e.url语句,启动自已基于ExtendedWebBrowser开发的浏览器程序,把各步骤中表单可以自动填单后的最后输出的那个URL记录下来,形成各步骤的特征URL,这样就能处理frames和Iframe及JS中加载的页面。如:
void brw_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (_windowManager.ActiveBrowser.ReadyState == WebBrowserReadyState.Complete)
{
SouthHIS.modOutputLog.OutputLog(e.Url.ToString());
}
}
记录下来的有:
步骤1:http://xxx.xxx/BasicInfo.aspx?OpFlag=add&strGuardNo=
步骤2:http://xxx.xxx/aaedit2.aspx
步骤2:http://xxx.xxx/aaedit3.aspx
3.各步骤填写表单有可能出错而要重复执行,如何让各步骤确定地执行完成上一步后再执行下一步并串起来.
解决:使用状态机方案,画好状态机图,然后定义一个变量表示状态机状态,执行成功一个步骤后,改变状态变量以让状态机执行下一动作,如果执行不成功,可以返回重新执行,或是返回上一步再重新加载等。
4.程序执行速度过快,即使程序表明页面载完成,自动填入表单时还是会发生一些页面里的onload时执行的未完成,导致后续填写表单或执行JS出错.即:判断出某步骤“加载完”最后的页面URL,执行填单程序,有时还是会出错,如何处理。
解决:使用多线程,让步骤执行在非主线程上执行,在满足载条件后再等待一段时间,让WebBrowser加载彻底完成后,再使用invoke来执行各步骤的填单程序.
样例程序:
public class InvokeObject
{
public System.Threading.ThreadStart m_func;
public MainForm m_frm;
public InvokeAA(System.Threading.ThreadStart func,MainForm frm)
{
m_func = func;
m_frm = frm;
}
public void ToThreadCall()
{
DateTime dt1 = DateTime.Now;
while (true)//等待“加载完成”后再等待200MS
{
Application.DoEvents();
DateTime dt2 = DateTime.Now;
TimeSpan ts = dt2.Subtract(dt1);
if (ts.Milliseconds > 200)
{
break;
}
}
m_frm.Invoke(m_func);//执行真正的步骤处理函
}
}
使用代码:
InvokeAA abc = new InvokeAA(GoToFamilyPage, this);//GoToFamilyPage是步骤处理函数
System.Threading.Thread th2 = new System.Threading.Thread(abc.ToThreadCall);
th2.Name = "GoToFamilyPage";
th2.Start();
5.如何拦截alert对话框,以让其继续.
解决:扩展WebBrowser,处理 ShowMessage.在extendedWebBrowser中,加入代码:
//拦截alert
#region ExtendedWebBrowserSite
class ExtendedWebBrowserSite : WebBrowser.WebBrowserSite, UnsafeNativeMethods.IDocHostShowUI
{
WebBrowser m_host;
public ExtendedWebBrowserSite(WebBrowser host)
: base(host)
{
m_host = host;
}
void UnsafeNativeMethods.IDocHostShowUI.ShowMessage(ref UnsafeNativeMethods._RemotableHandle hwnd, string lpstrText, string lpstrCaption, uint dwType, string lpstrHelpFile, uint dwHelpContext, out int plResult)
{
//TODO:自定义处理弹出消息框
//dwType:0x00000030问题
SouthHIS.modOutputLog.OutputLog(lpstrText);
SouthHIS.modOutputLog.OutputLog(dwType);
if (dwType != 0x00000030)
{
//plResult = (int)System.Windows.Forms.MessageBox.Show(lpstrText, lpstrCaption, (MessageBoxButtons)dwType );
}
plResult = 1;
}
void UnsafeNativeMethods.IDocHostShowUI.ShowHelp(ref UnsafeNativeMethods._RemotableHandle hwnd, string pszHelpFile, uint uCommand, uint dwData, UnsafeNativeMethods.tagPOINT ptMouse, object pDispatchObjectHit)
{
//TODO:自定义处理弹出帮助消息框
}
}
protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
{
return new ExtendedWebBrowserSite(this);
}
6.如何拦截执行JS出错时弹出的脚本错误对话框
解决:在加载页面前,使用:
brw.ScriptErrorsSuppressed = true;
让其不显示对话框.
7.如何取得frames,如何执行javascript,如何定义额外的javascript函数,如何取得执行javascript函数的返回值。
解决:
HtmlWindow win1 = _windowManager.ActiveBrowser.Document.Window.Frames[0];
mshtml.IHTMLWindow2 win2 = (mshtml.IHTMLWindow2)win1.DomWindow;
try
{
string script11 = "function SaveRow11() { return '0';}";
win2.execScript(script11, "javascript");
string strRetVal = (string)win1.Document.InvokeScript("SaveRow11");
if(strRetVal =='0')
{
....
}
}catch .....