selenium框架, Automation方式访问网页

解决方案 »

  1.   

    在CHtmlView::OnDocumentComplete事件处理函数中判断页面是否加载完全。
    virtual void OnDocumentComplete(LPCTSTR lpszURL);当Navigate打开一个URL后,比如www.baidu.com
    会触发很多次OnDocumentComplete,但最后一次触发(即百度首页全部加载完成)
    LPCTSTR lpszURL传进来的这个参数是"http:://www.baidu.com"
    由此可以来判断页面是否完全加载完毕
    如果加载完毕,再进行操作
      

  2.   

    我对网页进行了测试发现情况如下:
    http://10.22.8.11:7777/hdyh/
    登陆界面http://10.22.8.11:7777/hdyh/main2.jsp
    操作界面
    而在操作界面我无论点击按钮还是提交表单貌似url都没变啊。。那怎么判断?
      

  3.   

    我还发现一个问题,我为了测试程序代码我添加了MessageBox,代码如下
    /*第一步登陆网站*/
    ::CoInitialize(NULL); //初始化COM
    CComPtr<IHTMLDocument2> pIHTMLDocument2 =(IHTMLDocument2*)CHtmlView::GetHtmlDocument();
    HRESULT hr;
    bool id_name=false,id_pass=false;//验证用户信息填入
    //bool is_in=false;//验证是否登录成功 CComQIPtr<IHTMLElementCollection> spElementCollection;
    hr=pIHTMLDocument2->get_all(&spElementCollection);
    if(SUCCEEDED(hr))
    {   
    long nEleCount=0;//取得元素数目
    VARIANT index;
    hr=spElementCollection->get_length(&nEleCount); if(SUCCEEDED(hr))
    {
    for(long i=0; i<nEleCount; i++)
    {
    CComPtr<IDispatch> pDisp=NULL;//取得第i项表单
    V_VT(&index) = VT_I4;
    V_I4(&index) = i;

    hr = spElementCollection->item( index,index, &pDisp );//获取一个元素
    if (SUCCEEDED(hr))
    {
    CComQIPtr<IHTMLElement> pElem;         //网页元素

    hr = pDisp->QueryInterface(IID_IHTMLElement,(void **)&pElem );

    if (SUCCEEDED(hr))
    {
    BSTR className, tagName;
    pElem->get_tagName(&tagName);//标签名称匹配
    pElem->get_className(&className);//类名称匹配

    CString strTagName(tagName);//BSTR转换CString
    CString strClassName(className);

    if ("INPUT" == strTagName)//标签名称匹配貌似都是大写INPUT!!!!
    {
    CString strAttribute = "id";//属性id
    VARIANT ret;
    BSTR attribute = strAttribute.AllocSysString();//CString转换BSTR
    hr = pElem->getAttribute(attribute, 0 , &ret);//获取该类型的属性值
    if (ret.vt == VT_BSTR)
    {
    strAttribute = ((BSTR)ret.pcVal);
    }
    SysFreeString(attribute);
    if (SUCCEEDED(hr) && "TxtUserName" == strAttribute)//输入用户匹配
    {
    if (SUCCEEDED(hr))
    {
    CString str="chengxiaowei";
    BSTR bsStr = str.AllocSysString();
    pElem->put_innerText(bsStr);
    id_name=true;
    }
    }
    if (SUCCEEDED(hr) && "TxtPassword" == strAttribute)//输入密码匹配
    {
    if (SUCCEEDED(hr))
    {
    CString str2="111111";
    BSTR bsStr2 = str2.AllocSysString();
    pElem->put_innerText(bsStr2);
    id_pass=true;
    }
    }
    if (SUCCEEDED(hr) && "IbtnEnter" == strAttribute)//按钮匹配
    {
    if(id_name && id_pass)
    {
    pElem->click();
    is_in=true;
    }
    }
    }
    }
    }
    }
    }
    }
    ::CoUninitialize();   //释放COM //Sleep(2000);

    ::CoInitialize(NULL); //初始化COM
    /*第二步菜单选择*/
    //操作脚本
    //bool is_second=false;
    if(is_in && m_nCount==1)
    {
    CComQIPtr<IHTMLDocument2> spDoc =(IHTMLDocument2*)CHtmlView::GetHtmlDocument();;
    CComPtr<IDispatch> spScript;

    hr=spDoc->get_Script(&spScript);

    if(SUCCEEDED(hr))
    {
    MessageBox("1","test",MB_OK);
    //测试发现增加对话框可以实现,是否时间不够
    CComBSTR bstrMember("loadFrame");
    DISPID dispid = NULL;
    hr = spScript->GetIDsOfNames(IID_NULL,&bstrMember,1,LOCALE_SYSTEM_DEFAULT,&dispid);
    Sleep(200);

    if(SUCCEEDED(hr))
    {
    //MessageBox("1","show",MB_OK);
    DISPPARAMS dispparams;
    memset(&dispparams, 0, sizeof dispparams);
    dispparams.cArgs = 1;//表示参数的计数
    dispparams.rgvarg = new VARIANT[dispparams.cArgs];//表示对参数数组的引用

    for( int i = 0; i < 1; i++)
    {
    CString param1="jsp/ss/rz/rz_all.jsp";
    CComBSTR bstr_param1=param1.AllocSysString();
    bstr_param1.CopyTo(&dispparams.rgvarg[i].bstrVal);
    dispparams.rgvarg[i].vt = VT_BSTR;


    dispparams.cNamedArgs = 0;//表示命名参数的计数
    EXCEPINFO excepInfo;
    memset(&excepInfo, 0, sizeof excepInfo);
    CComVariant vaResult;
    UINT nArgErr = (UINT)-1;  // initialize to invalid arg
    hr = spScript->Invoke(dispid,IID_NULL,0,DISPATCH_METHOD,&dispparams,&vaResult,&excepInfo,&nArgErr);

    if(SUCCEEDED(hr))
    {
    is_second=true;
    }

    delete [] dispparams.rgvarg;
    }
    }
    }
    ::CoUninitialize();   //释放COM
    我发现在红字代码加了之后弹出MessageBox之后可以实现第二步骤,否则代码不实行第二步骤。这个没搞懂。
      

  4.   

    我对网页进行了测试发现情况如下:
    http://10.22.8.11:7777/hdyh/
    登陆界面http://10.22.8.11:7777/hdyh/main2.jsp
    操作界面
    而在操作界面我无论点击按钮还是提交表单貌似url都没变啊。。那怎么判断?
    URL没变说明页面是AJAX动态加载的,点击按钮时JS会向服务器请求内容,这种情况下CHtmlView::OnDocumentComplete事件也是能触发的,URL是什么不知道的话,你可以调试一下看看,点一个按钮试试,记录下页面加载过程中最后一个OnDocumentComplete事件传进来的LPCTSTR lpszURL参数
      

  5.   

    比如在CHtmlView::OnDocumentComplete里打下断点。
    点调试运行程序,鼠标点一下网页上的某个按钮,页面加载完后CHtmlView::OnDocumentComplete中断点会断下,然后看下它的LPCTSTR lpszURL参数
      

  6.   

    我研究了下发现确实有不同,现在遇到一个新的问题就是网页中会Alert出消息对话框,如何自动点击确认或者关闭掉。
      

  7.   

    我今天用SendMessage函数,先找到Alert提示对话框句柄,然后再找到按钮句柄,模拟按钮点击为什么没有反应呢。代码如下
    //查找Alert窗口并关闭
    HWND g_hWndWindow = ::FindWindow(NULL,"来自网页的消息");//查找对话框句柄
    if(g_hWndWindow!=0) 
    {
    HWND g_hWndText = ::FindWindowEx(g_hWndWindow,NULL,NULL,"保存成功");//查找按钮
    if(g_hWndText!=0) 
    {
    ::SendMessage(g_hWndText,WM_KEYDOWN,VK_RETURN,NULL);
    ::SendMessage(g_hWndText,WM_KEYUP,VK_RETURN,NULL);
    KillTimer(1);//关闭定时器
    }
    }
      

  8.   

    我测试了发现代码
    ::SendMessage(g_hWndWindow, WM_CLOSE, 0, 0);
    这句可以关闭窗口。
    ::PostMessage(g_hWndText,BM_CLICK,0,0);//点击按钮
    没反应这是怎么回事。
      

  9.   

    你可以用SPY++看一看,点确定按钮时,按钮上并没有收到BM_CLICK消息,而是对话框窗口收到了WM_COMMAND消息,其中NotifyCode为BN_CLICKED。为了关闭这个对话框,方法很多,直接对对话框发送WM_CLOSE消息或WM_COMMAND消息,或对上面的按钮发送WM_LBUTTONDOWN WM_LBUTTONUP消息等等。但是这些办法都是等对话框出现了才去关闭,多少都会闪一下。最好的办法是让它彻底不弹出。方式是动态修改HMTL的内容,把Alert去掉。
    更简单一点就是在HTML中动态加入Alert函数的新定义,把原本的Alert覆盖掉。
    比如在HTML中加入:<script type="text/javascript">
        function alert(str) { ; }
    </script>这样,整个页面上的Alert就不会弹出任何东西了
      

  10.   

    我现在遇到一个问题,表单连续录入发现无法实现连贯性。也就是网页中有三个按钮分别为新建,保存,返回。网页内容输入后调用按钮保存,弹出Alert对话框,查找窗口关闭后调用新建按钮,继续网页内容输入调用按钮保存,这样重复循环操作。我代码测试后无法实现。不知道是代码问题还是什么,请问你有什么思路吗。我的思路在OnTimer里添加循环但是测试了无法实现连续性一直断在关闭Alert代码处。
      

  11.   

    我测试发现我点击了保存按钮弹出了保存成功对话框,但是网页上通过查询却看不到我录入的信息,这是怎么回事。
    代码如下/*第五步台账登陆*/
    ::CoInitialize(NULL); //初始化COM
    if(is_fourth && cs_url=="http://10.22.8.11:7777/hdyh/jsp/ss/rz/jdby_new.jsp")//m_nCount==7
    {
    CComQIPtr<IHTMLDocument2> spHMDoc =(IHTMLDocument2*)CHtmlView::GetHtmlDocument();;
    CComPtr<IHTMLFramesCollection2> spHMFramesCollection2;   
    spHMDoc->get_frames(&spHMFramesCollection2); //取得框架frame的集合

    long nHMFrameCount;        //取得子框架个数
    nHMFrameCount=0;
    hr=spHMFramesCollection2->get_length(&nHMFrameCount);   
    if (FAILED(hr)|| 0==nHMFrameCount) return;   

    for(long i=0; i<nHMFrameCount; i++)   
    {   
    CComVariant vHMDispWin2; //取得子框架的自动化接口   
    hr = spHMFramesCollection2->item(&CComVariant(i), &vHMDispWin2);   
    if (FAILED(hr)) continue;       
    CComQIPtr<IHTMLWindow2> spHMWin2 = vHMDispWin2.pdispVal;   
    if (!spHMWin2) continue; //取得子框架的   IHTMLWindow2   接口       
    CComPtr<IHTMLDocument2> spHMDoc2;   
    spHMWin2->get_document(&spHMDoc2); //取得子框架的   IHTMLDocument2   接口

    //测试是否在下一层框架
    CComPtr<IHTMLFramesCollection2> sHMFramesCollection2;   
    spHMDoc2->get_frames(&sHMFramesCollection2); //取得框架frame的集合

    long nHMFrameCount2=0;        //取得子框架个数   
    hr=sHMFramesCollection2->get_length(&nHMFrameCount2);
    if(SUCCEEDED(hr))
    {
    for(long i2=0; i2<nHMFrameCount2; i2++)
    {
    CComVariant vpHMDispWin2; //取得子框架的自动化接口   
    hr = sHMFramesCollection2->item(&CComVariant(i2), &vpHMDispWin2);
    if(SUCCEEDED(hr))
    {
    CComQIPtr<IHTMLWindow2> sHMWin2 = vpHMDispWin2.pdispVal;

    CComPtr<IHTMLDocument2> sHMDoc2;
    sHMWin2->get_document(&sHMDoc2); //取得子框架的   IHTMLDocument2   接口

    CComQIPtr<IHTMLElementCollection> spHMElementCollection;
    hr=sHMDoc2->get_all(&spHMElementCollection);
    if (SUCCEEDED(hr))
    {
    long nHMEleCount=0;           //取得元素数目
    VARIANT HMindex;
    hr=spHMElementCollection->get_length(&nHMEleCount);

    if (SUCCEEDED(hr))
    {
    //测试是否此处可进行循环登记//////
    int in_i;//switch里面不可变量定义和初始化一步
    for(in_i=0;in_i<stringArray.size()/2;in_i++)
    {
    for(long i3=0; i3<nHMEleCount; i3++)
    {
    IDispatch *pHMDisp = NULL;   //取得第i项表单
    V_VT(&HMindex) = VT_I4;
    V_I4(&HMindex) = i3;

    hr = spHMElementCollection->item(HMindex,HMindex, &pHMDisp );//Get an element
    IHTMLElement* pHMElem;         //网页元素
    hr = pHMDisp->QueryInterface(IID_IHTMLElement,(void **)&pHMElem );
    BSTR className, tagName;
    pHMElem->get_tagName(&tagName);//标签名称匹配
    pHMElem->get_className(&className);//类名称匹配

    CString strTagName(tagName);//BSTR转换CString
    CString strClassName(className); if(!is_new)
    {
    if ("INPUT" == strTagName)//标签名称匹配貌似都是大写INPUT
    {
    CString strAttribute = "id";//属性
    VARIANT ret;
    BSTR attribute = strAttribute.AllocSysString();//CString转换BSTR
    hr = pHMElem->getAttribute(attribute, 0 , &ret);//获取该类型的属性值
    if (ret.vt == VT_BSTR)
    {
    strAttribute = ((BSTR)ret.pcVal);
    }
    SysFreeString(attribute);

    if (SUCCEEDED(hr) && "qsrq" == strAttribute)//匹配
    {
    CString str=stringArray.at(in_i*2);//"2014-02-19 09时"
    BSTR bsStr = str.AllocSysString();
    pHMElem->put_innerText(bsStr);
    num_infoin++;
    }
    .........
        if ("TEXTAREA" == strTagName)
    {
        CString strAttribute3 = "id";//属性
        CString str="设备运行正常";//值班内容
        BSTR bsStr = str.AllocSysString();
    CString str2="无";
    BSTR bsStr2 = str2.AllocSysString();

    VARIANT ret3;
    BSTR attribute3 = strAttribute3.AllocSysString();//CString转换BSTR
    hr = pHMElem->getAttribute(attribute3, 0 , &ret3);//获取该类型的属性值
    if (ret3.vt == VT_BSTR)
    {
    strAttribute3 = ((BSTR)ret3.pcVal);
    }
    SysFreeString(attribute3);

    if (SUCCEEDED(hr) && "fdjzqk" == strAttribute3)//匹配
    {
    pHMElem->put_innerText(bsStr);
    num_infoin++;
    }
    }

    if(num_infoin%14==0)//判断信息录入完全后进行点击保存
    {
    if ("IMG" == strTagName)
    {
    CString strAttribute4 = "id";//属性
    VARIANT ret4;
    BSTR attribute4 = strAttribute4.AllocSysString();//CString转换BSTR
    hr = pHMElem->getAttribute(attribute4, 0 , &ret4);//获取该类型的属性值
    if (ret4.vt == VT_BSTR)
    {
    strAttribute4 = ((BSTR)ret4.pcVal);
    }
    SysFreeString(attribute4);

    if (SUCCEEDED(hr) && "save" == strAttribute4)//id匹配
    {
    pHMElem->click();
    is_new=true;
    num_win++;
    }
    }
    }
    } if(is_new)
    {
    //查找Alert窗口并关闭///////////////////////////////////////////////////
    HWND g_hWndWindow = ::FindWindow(NULL,"来自网页的消息");//查找对话框句柄
    if(g_hWndWindow!=0) 
    {
    HWND g_hWndText = ::FindWindowEx(g_hWndWindow,NULL,NULL,"保存成功");//查找按钮
    if(g_hWndText!=0) 
    {
    //MessageBox("1","1",MB_OK);
    ::SendMessage(g_hWndWindow, WM_CLOSE, 0, 0);//关闭窗口
    num_win++;
    }
    }
    }

    //////////////////////////////////
    if(is_new && num_win%2==0)//判断保存按钮后并且关闭提示框后点击新建按钮
    {
    if ("IMG" == strTagName)
    {
    CString strAttribute5 = "id";//属性
    VARIANT ret5;
    BSTR attribute5 = strAttribute5.AllocSysString();//CString转换BSTR
    hr = pHMElem->getAttribute(attribute5, 0 , &ret5);//获取该类型的属性值
    if (ret5.vt == VT_BSTR)
    {
    strAttribute5 = ((BSTR)ret5.pcVal);
    }
    SysFreeString(attribute5);

    if (SUCCEEDED(hr) && "new" == strAttribute5)//id匹配
    {

    pHMElem->click();
    is_new=false;
    num_infoin=0;

    if(in_i==stringArray.size()/2-1)
    {
    KillTimer(1);
    }
    break;
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    ::CoUninitialize();   //释放COM
      

  12.   

    这个只能是你自己慢慢研究,调试了。
    调试一下看看,不能持续循环录入时,代码是停在了哪里。
    错误处理完善一点,认真处理每一处可能出现错误的地方,判断每一个返回的指针是否为空,每一处出错后执行断言或抛出异常,这样有助于找到错误所在。
    另外,页面或页面上的框架的内容重新加载、刷新后,之前获取的有关该文档上的各种元素指针可能失效。
    进行一次录入-提交后,一定要等页面加载完成,触发CHtmlView::OnDocumentComplete事件才可进行下一轮录入提交操作,或是留出足够长的时间间隔。
    还有就是你的代码嵌套层次太深了,不利于调试、排错,重构一下,拆分为多个小函数
      

  13.   

    恩,我今天早上调试了。找到问题了。但是不知道原因。你看看为什么。
    if(is_new)
    {
    HWND g_hWndWindow = ::FindWindow(NULL,"来自网页的消息");//查找对话框句柄
    if(g_hWndWindow!=0) 
    {
    HWND g_hWndText = ::FindWindowEx(g_hWndWindow,NULL,NULL,"保存成功");//查找按钮
    if(g_hWndText!=0) 
    {
    ::SendMessage(g_hWndWindow, WM_CLOSE, 0, 0);//关闭窗口
    num_win++;
    //MessageBox("5","show",MB_OK);
    }
    }
    }
    这段代码主要用于关闭Alert窗口,我设定当关闭一次时num_win计数加一,用于后续操作判断。但是我调试了发现当第一次弹出Alert窗口后,代码获取到然后发送关闭窗口后,计数加了1,后面定时器继续调试时,莫名这段代码又被调用一次,照理说,窗口句柄应该找不到了,因为窗口被关闭了,但是我猜是不是SendMessage发送的销毁指令和定时器是异步啊。所以在销毁指令前又调用了一次。
    另外因为网站是内网,我下班之后也调试不了。上班之后需要另外接线,调试时相当麻烦。郁闷。
    还有就是关于嵌套我也感觉是有点多,但是我查了下我处理得网站是框架中套框架,你的意思是让我自定义函数然后重复调用?
      

  14.   

    我现在又发现一个问题,就是处理网页时,网页中表格Table点击其中某一个单元格,发现我获取元素接口之后Click发现没反应。
    该单元格源文件中代码如下:
    <td align="center">
                       <A  href="yhd.jsp?fm=1&dwdm2=BZ01&qssj=2014-01-01&zzsj=2014-03-17">0</A>
                    </td>
                    <td align="center">
                       <A  href="fmjc.jsp?fm=1&dwdm2=BZ01&qssj=2014-01-01&zzsj=2014-03-17">0</A>
                    </td>
    它就是一个链接形式,但是每一天链接形式貌似不一样有日期后缀,所以不能判断固定网址。我不知道如何点击该单元格了。了
      

  15.   

    获取到单元格tb标签的元素后,还的获取到其中包含的<A>标签元素指针,再Click
      

  16.   

    如何获取A标签的指针?没有id之类的东西啊。。
      

  17.   

    IHTMLElement::get_children即可获取td标签元素内的a标签元素td标签元素不是也没有ID吗,你是怎么获取的呢?
      

  18.   

    我还是有点不太理解,我知道遍历,问题是我如何知道搜索到的是我要的指针接口。譬如搜索到了20个节点,我怎么知道循环中第几个是我要的接口。
    我的代码如下
    //搜索表格内容
    IDispatch *pDisp;
    VARIANT index;  
    _variant_t varID = "mytab"; // 表格元素ID 
    V_VT(&index) = VT_I4;  
    V_I4(&index) = 0;  
    hr = spElementCollection->item(varID, index, &pDisp);                  // 获得表格位置  
    if (SUCCEEDED(hr) && (pDisp != NULL))  
    {  
    IHTMLTable * pTable;                                           // 获得表格元素接口  
    hr = pDisp->QueryInterface(IID_IHTMLTable,(void **)&pTable );  
    if (SUCCEEDED(hr) && (pTable != NULL))  
    {  
    IHTMLElementCollection* pColl2;  
    pTable->get_rows(&pColl2);                                 // 获取表格行  
    IDispatch* pDisp2; 
    VARIANT index2;
    V_VT(&index2)=VT_I4;
    V_I4(&index2) = 1;  
    hr = pColl2->item( index2,index2, &pDisp2 );                 // 获取第2行位置  
    if ( (SUCCEEDED(hr)) && (pDisp2 != NULL) )  
    {//必须保证hr成功和pDisp不为NULL
    IHTMLTableRow* pRow;                                   // 获取行元素接口  
    hr = pDisp2->QueryInterface(IID_IHTMLTableRow,(void **)&pRow);  
    if( (SUCCEEDED(hr)) && (pRow != NULL) )  
    {  
    IHTMLElementCollection* pColl3;  
    pRow->get_cells(&pColl3);                          // 获取格子元素  
    IDispatch* pDisp3;  
    VARIANT index3;
    V_VT(&index3)=VT_I4;
    V_I4(&index3) = 8;  
    hr = pColl3->item( index3,index3, &pDisp3 );         // 获取第2行第(7,8)格元素  
    if ( (SUCCEEDED(hr)) && (pDisp2 != NULL) )  
    {  
    IHTMLElement* pElem;                           // 获取元素接口  
    hr = pDisp3->QueryInterface(IID_IHTMLElement,(void **)&pElem);  
    if(SUCCEEDED(hr))  
    {
    pElem->click();
    is_third=true;
    }
    }
    }
    }
    }
    }
      

  19.   

    我看了下网上代码最后通过innerText来判断是否为获取到的A标签,我这个源文件上文本为0.这个怎么搞?我现在自己测试的在找到表格中第几行第几个单元格之后用你说的get_chirldren获取不到啊
      

  20.   

    首先,你要获取到td标签元素的IHTMLElement指针,然后调用get_chirldren获取到一个IDispatch指针,QueryInterface得到IHTMLElementCollection元素容器指针,然后用IHTMLElementCollection::item获取容器内a标签元素指针。至于在一个循环遍历中,如何知道哪个是你要的元素,可以根据这个元素的特征来判断,innerText也是一种方法,如果innerText获取不到字符串的话,尝试get_innerHTML、get_outerHTML、get_outerText。一般它的html写的比较标准的话,是能获取到的。
    但是有的html写的不太标准的,确实会出现获取不到任何内容的情况。
      

  21.   

    是啊我这发现这个网页写的不规范啥都没有。不知道如何判断。我现在又发现网页中一个图片没有信息可以进行判断它的html代码为
    <td align=center width=80>
    <img src="../../../css/images/tjby.jpg"  onclick="tjby();" style="cursor:hand;" align="absbottom">
    </td>
    至于之前的A标签我实现点击了但是我发现一个问题,为何用IHTMLElementCollection::item获取容器内a标签元素指针时候,我判断了下元素集合的大小,发现为0但是取第一个值能click所以我很晕,忙了半天以为没取到谁知道已经取到指针了
      

  22.   

    这个img标签元素,你可以根据它的"属性"来判断,src、style、align这些都是它的属性。
    其中src属性可以明确区分出来。可以用IHTMLElement::getAttribute取属性进行判断。
    或是QueryInterface得到这个img标签元素的IHTMLImgElement指针后,用IHTMLImgElement::get_src获取进行判断。有时候使用mshtml出现空指针、找不到元素、返回内容为空的情况时,可以手写一个简单的html文件进行测试、分析问题出在哪里。实在不行的话用javascript试试看看能不能实现,总之mshtml能实现的功能,javascript几乎都能实现,并且javascript就是专门搞这个的。