C++ 利用COM接口操作网页元素的问题

inpile99 2012-04-14 10:14:47
前两日,写一个遍历网页元素的代码,遇到问题,不得解、、、、、

实现代码所遍历的网页是直接遍历IE实例个数来完成。即利用 CComPtr< IShellWindow >。也就是说,假设须要遍历的网页记为网页 A。则网页A是通过浏览器方式打开的,而并非程序所用控件打开。

通过CComPtr< IShellWindow >, 得到了网页A的 CComPtr< IWebBrowser >、、、
再通过CComPtr< IWebBrowser >,得到了一个 IDispatch,再通过其得到 CComQIPtr< IHTMLDocument2 >;
至此,已得到指向A页面的IHTMLDocument2 的指针。通过其 get_title( &BSTR ),可以正常得到网页A的标题、、、

问题如下:
第一次的做法:
当我遍历IHTMLDocument2时,
使用 IHTMLDocument2 的 get_length( &long ),得到其 IHTMLFramesCollection2集合个数。 发现值是 3;
在调用IHTMLFramesCollection2 的方法 item( iNdex, ( void ** )IHTMLWindow2 ), 循环 3 次,可正常得到3个指向
IHTMLWindow2的指针( 准确来说是非0值,值看起来似乎正常 )。
每次当我再调用IHTMLWindow2的 get_document( IHTMLDocument2 ),欲获得相对应的IHTMLDocument2的指针时,三次均得到一个空指针、、、、、、、

后来,尝试如下:
第一次得到IHTMLDocument2 的指针时,便不对它进行遍历,直接调用 elementFromPoint( long x, long y, IHTMLElement ); 而 x , y ,均以零开始,扫描从坐标 (0,0) 一直到 (3000, 5000),x 以 +10递增,y 以加2递增。
可得到的IHTMLElement, 再调用其tagName方法,显示发现,每次循环调用得到的标签元素似乎总是 HTML、DIV、IFRAME、H、A等之类的,但对于 Input、Form 之类的却得不到、、、(当然,我确定页面上是存在诸多类似标签的)所以,有点不解elementFromPoint的用法,是不是它只能得到HTML、DIV等之类的标签?我用这个函数时,知道它可能登不了台的,但还是试了下、、、、、、
我继续用第一次得到的IHTMLDocument2的指针, 调用get_cookie( &BSTR ),可以正常得到该页面的COOKIE;
但如果遍历网页B时,得到其IHTMLFramesCollection2的个数是2,,该代码却能正常遍历出所有Input元素、、、
于是,我迷忽了、、、、、
我在想这个问题:
网页A,它的Frames 为 3。一个页面,它引入了3个其它独立页面,如网页头是单独的,网页正文内容,再加上网页底部的版权信息,而Input之类的元素都在正文的页面当中,所以,遍历不出来
而网页B,它的Frames 为2,它引入了两个独立页面,正文 和 网页底部信息。此时,Input的元素均在 正文部分,所以,可以正常遍历出Input元素、、、、、
不知道我有没有说明白,也不知道有没有办法可以解决一个问题:只要一个网页A,在浏览器内可以显示出来的Input元素,我们都可以操作它??不管它网页是使用了什么样的技术。
或是,网页开发过程中,有木有一种技术可以屏蔽其它软件得到其Input元素???(因为网页A应该有安全机制的,你懂的)-------这个问题最重要、、、、、


比如,我帖个Google的网址: http://www.google.com.hk/ig?hl=zh-CN&source=webhp&refresh=1
在上面这个网页中,填入搜索关键字的那个Input元素可以正常得到,但是,该页面下面引用的一些模块的元素就无法得到了。下面将代码贴下,当然,假设我知道遍历元素的类型不同获得方法也不同 如Select元素、input 、、、






#include "GetElement.h"
#include <iostream>
using namespace std;

BOOL TraversalDocument( CComQIPtr< IHTMLDocument2 > pDoc2 );

int main()
{
//SHDocVw:IShellWindowsPtr m_sp;
::CoInitialize( NULL );
CComPtr< IShellWindows > pShellWin;
CComPtr< IDispatch > pDispatch;
CComQIPtr< IWebBrowser2 > pWebBro;
CComQIPtr< IHTMLDocument2 > pDoc2;


HRESULT hr = pShellWin.CoCreateInstance( CLSID_ShellWindows );
if ( FAILED( hr ) )
{
cout << "IShellWindows CoCreateInstance Error" << endl;
goto _MainExit;
}


long lInstanceCount = 0;
pShellWin->get_Count( &lInstanceCount );
for ( long lIndex = 0; lIndex < lInstanceCount; lIndex++ )
{
pDispatch.Release();
hr = pShellWin->Item( CComVariant( lIndex ), &pDispatch );
if ( FAILED( hr ) )
{
continue;
}

pWebBro.Release();
pWebBro = pDispatch;
if ( !pWebBro )
{
continue;
}

pDispatch.Release();
hr = pWebBro->get_Document( &pDispatch );
if ( FAILED( hr ) )
{
continue;
}

pDoc2.Release();
pDoc2 = pDispatch;
if ( !pDoc2 )
{
continue;
}

TraversalDocument( pDoc2 );

}


_MainExit:

// ::CoUninitialize();
system( "pause" );
return 0;
}

BOOL TraversalDocument( CComQIPtr< IHTMLDocument2 > pDoc2 )
{
CComQIPtr< IHTMLFramesCollection2 > pFramCol2;

pFramCol2.Release();
HRESULT hr = pDoc2->get_frames( &pFramCol2 );
if ( FAILED( hr ) )
{
return FALSE;
}

long lFramCount = 0;
hr = pFramCol2->get_length( &lFramCount );
if ( FAILED( hr ) )
{
return 0;
}

if ( lFramCount )
{
CComQIPtr< IHTMLDocument2 > pTraDoc2;
CComQIPtr< IHTMLWindow2 > pWin2;
VARIANT varIndex;
VARIANT varDisp;
varIndex.vt = VT_I4;
varDisp.vt = VT_DISPATCH;
for ( int iIndex = 0; iIndex < lFramCount; iIndex++ )
{
varIndex.intVal = iIndex;
varDisp.pdispVal = NULL;
hr = pFramCol2->item( &varIndex, &varDisp );
if ( FAILED( hr ) )
{
continue;
}

pWin2.Release();
pWin2 = varDisp.pdispVal;
pTraDoc2.Release();
hr = pWin2->get_document( &pTraDoc2 );
if ( FAILED( hr ) )
{
continue;
}

TraversalDocument( pTraDoc2 );
}
}

CComQIPtr< IHTMLElementCollection > pEleColl;
pEleColl.Release();
hr = pDoc2->get_forms( &pEleColl );
if ( FAILED( hr ) )
{
return FALSE;
}

CComQIPtr< IHTMLFormElement > pFormEle;
long lFormCount = 0;
hr = pEleColl->get_length( &lFormCount );
if ( FAILED( hr ) )
{
return FALSE;
}

CComPtr< IDispatch > pDis;
CComQIPtr< IHTMLInputElement > pInput;
VARIANT varName;
varName.vt = VT_BSTR;
varName.bstrVal = NULL;
VARIANT varIndex;
varIndex.vt = VT_I4;
BSTR bsStr;
char* lpszText2;
for ( long lFormIndex = 0; lFormIndex < lFormCount; lFormIndex++ )
{
pDis.Release();
hr = pEleColl->item( CComVariant( lFormIndex ), CComVariant(), &pDis );
if ( FAILED( hr ) )
{
continue;
}

pFormEle.Release();
pFormEle = pDis;
if ( !pFormEle )
{
continue;
}

long lEleCount = 0;
hr = pFormEle->get_length( &lEleCount );
if ( FAILED( hr ) )
{
continue;
}
for ( long lEleIndex = 0; lEleIndex < lEleCount; lEleIndex++ )
{
CComDispatchDriver spInputElement;
hr = pFormEle->item( CComVariant( lEleIndex ), CComVariant(), &spInputElement );
if ( FAILED( hr ) ) continue;

CComVariant vName,vVal,vType;
hr = spInputElement.GetPropertyByName( L"name", &vName );
if( FAILED( hr ) ) continue;
hr = spInputElement.GetPropertyByName( L"value", &vVal );
if( FAILED( hr ) ) continue;
hr = spInputElement.GetPropertyByName( L"type", &vType );
if( FAILED( hr ) ) continue;

if ( vName.bstrVal != NULL )
{
lpszText2 = _com_util::ConvertBSTRToString(vName.bstrVal);
cout<< "Name:" << lpszText2;
}
if ( vVal.bstrVal != NULL )
{
lpszText2 = _com_util::ConvertBSTRToString(vVal.bstrVal);
cout<< " Value:" << lpszText2;
}
if ( vType.bstrVal != NULL )
{
lpszText2 = _com_util::ConvertBSTRToString(vType.bstrVal);
cout<< " Type:" << lpszText2 << endl;
}
}

}

return FALSE;
}

...全文
716 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
stunix 2014-09-30
  • 打赏
  • 举报
回复
没看清这都是12年的帖子了 咋么还没结贴
stunix 2014-09-30
  • 打赏
  • 举报
回复
引用 1 楼 inpile99 的回复:
不能沉的啊、、、、、、 我刚刚再次用elementFromPoint这个函数扫描了一次,发现,得到了一个IFrame。并得到了它的ID 然后,我又查看网页源文件,发面里面的确有这个IFrame,而我可以很负责任的说,Input的元素,就是在这个Iframe里面,它也的确是从其它位置引入的块、、、、、 当我查MSDN,得到 IHTMLIFrameElement, IHTMLIFrameElement2这两个东东,查这两个东东发现它的方法少之又少,实在想不到怎样通过这个IHTMLFrameElement函数得到其引入的页面的Document指针、、、、、、、求大牛们指点一二呐、、、、 俺继续中、、、、、、
我正在写关于这个的动态库 给你贴一小段我的代码

CComVariant result;
CComPtr<IDispatch> MyDisp;
htFrame->item(&CComVariant(i),&result);
MyDisp = result.pdispVal;
CComQIPtr<IHTMLWindow2>  frmWnd(MyDisp);
if (frmWnd)
{
	hr  = frmWnd->get_document(&spFrmDoc);
	if (FAILED(hr)) continue;
}
Afterwards_ 2012-09-30
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

引用 4 楼 的回复:
引用 3 楼 的回复:

现在的问题是、、、、、在C++中,如何通过IFrame来得到其Document2 的一个指针呢、、、、、、、


强制跃层可以解决你的问题.


不过,你应该知道淘宝网 尽管他是多层嵌套 你也能得到全部的元素,如果你是使用的是WEB控件的内在打开网页的功能,那么就已经加载了全部.然后你用一个get_all来加载所有的元素 其次……
[/Quote]

好高深 其实网页语言我一点都不懂 JS都不知道是啥 只是写一些我平时工作用的到的软件 所以才有研究
inpile99 2012-09-23
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]
引用 3 楼 的回复:

现在的问题是、、、、、在C++中,如何通过IFrame来得到其Document2 的一个指针呢、、、、、、、


强制跃层可以解决你的问题.


不过,你应该知道淘宝网 尽管他是多层嵌套 你也能得到全部的元素,如果你是使用的是WEB控件的内在打开网页的功能,那么就已经加载了全部.然后你用一个get_all来加载所有的元素 其次得到元素个数 然后按照总数进行……
[/Quote]

如果你提出的 强制跃层 这个问题可以解决的话,后续再找你交流、、、、
关于通过IFrame得到该嵌入子网页的指针,我后来是通过如下方法实现的。通过COM控制浏览器,针对某一网页,在本地植入JS代码,而用JS代码来处理IFrame子网页的元素,然后再用C++调用传入的该JS代码,JS代码将结果返回给C++程序,如此,就解决了我当时的问题、、、、、
Afterwards_ 2012-09-22
  • 打赏
  • 举报
回复
楼主还没搞定? 或许你可以用 IHTMLEFrameBase 到 IHTMLDocunemt
Afterwards_ 2012-08-10
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

现在的问题是、、、、、在C++中,如何通过IFrame来得到其Document2 的一个指针呢、、、、、、、
[/Quote]

强制跃层可以解决你的问题.


不过,你应该知道淘宝网 尽管他是多层嵌套 你也能得到全部的元素,如果你是使用的是WEB控件的内在打开网页的功能,那么就已经加载了全部.然后你用一个get_all来加载所有的元素 其次得到元素个数 然后按照总数进行便利即可 动态页建议get_outerHTML和innerHTML查看获取到的代码内容
inpile99 2012-04-14
  • 打赏
  • 举报
回复
现在的问题是、、、、、在C++中,如何通过IFrame来得到其Document2 的一个指针呢、、、、、、、
Kaile 2012-04-14
  • 打赏
  • 举报
回复
如果只取html中的值,com过于复杂,过于难用。

可以搜索一些开源的库
inpile99 2012-04-14
  • 打赏
  • 举报
回复
不能沉的啊、、、、、、

我刚刚再次用elementFromPoint这个函数扫描了一次,发现,得到了一个IFrame。并得到了它的ID

然后,我又查看网页源文件,发面里面的确有这个IFrame,而我可以很负责任的说,Input的元素,就是在这个Iframe里面,它也的确是从其它位置引入的块、、、、、

当我查MSDN,得到 IHTMLIFrameElement, IHTMLIFrameElement2这两个东东,查这两个东东发现它的方法少之又少,实在想不到怎样通过这个IHTMLFrameElement函数得到其引入的页面的Document指针、、、、、、、求大牛们指点一二呐、、、、
俺继续中、、、、、、
Delphi XE2 正式版的破解程序,有效哦。 Delphi XE2 官方完整 delphicbuilder_xe2_win_dl.iso下载地址: http://altd.embarcadero.com/download/radstudio/xe2/delphicbuilder_xe2_win_dl.iso 文件大小: 2.33G MD5: de8b9f897e2ad678643b64898470b707 Delphi Prism XE2 - ISO 1.28G http://altd.embarcadero.com/download/prism/xe2/prism_xe2_win.iso RadPHP XE2 - ISO 343M http://altd.embarcadero.com/download/radphp/xe2/radphp_xe2_win.iso 建议大家用迅雷下载 ************************************** 英巴卡迪诺发布新版RAD Studio XE2开发工具套件 日前,英巴卡迪诺宣布发布新版RAD Studio XE2软件开发工具套件,新版包含了10多年来最深入全面的特性升级。RAD Studio XE2中包含了新版本的Delphi、C++Builder、Prism和RadPHP。主要特性包括完整的Delphi 64位Windows支持,通过全新的FireMonkey富商业应用平台支持Mac OSX和iOS,以及通过RadPHP XE2支持安卓web和移动应用开发。 对Delphi XE2和C++Builder XE2来说,一个极其重要的新特性就是FireMonkey,业界第一款用于创建商业软件的原生的能全面利用到CPU和GPU计算能力的富应用平台。使用 FireMonkey,Delphi和C++Builder开发人员能开发出视觉绚丽的高清和3D应用程序,并与后台的企业级数据库如Oracle、微软 SQL Server、IBM DB2、Sybase和其他数据库互联互通。FireMonkey应用以原生方式运行在Windows PC和Mac上,可以完全利用到现代GPU的处理能力,以不可置信的细节处理能力和优异的性能表现展现数据和用户界面。FireMonkey还可以使 Delphi XE2用户为移动(iOS)设备创建原生的高清和3D应用程序。 Delphi和C++Builder为应用开发提供原生开发方式,而RadPHP XE2则支持web开发和移动设备应用的开发。使用RadPHP XE2,开发人员可以轻松为移动智能电话和平板电脑创建支持触碰和UI优化的web应用。开发人员可以部署他们的移动Web应用为原生移动应用到苹果公司的iOS应用商店和安卓的应用市场。在他们的移动Web应用中,可以直接访问移动设备的硬件,如相机、GPS和重力感应器。 其他新增特性包括: Delphi XE2 和C++Builder XE2 Delphi XE2包括完整的Windows 64位对FireMonkey、编译器、调试器、RTL 和VCL的支持; dbExpress具有新的对InterBase XE, FireBird 2.5, SQL Anywhere 12 和ODBC的连接能力; 新的DataSnap移动连接器,带有原生的平台组件和示例以创建从移动客户端到Delphi DataSnap服务器的连接,支持安卓(Java), iOS (Objective C), 黑莓(Java) 和Windows Phone 7 (C#); 新增和更新的扩展工具,包括FastReport,用于快速设计和生成报表;Documentation Insight,用于Delphi的源代码文档工具; TeeChart、IBX、InstallAware、IP*Works、Aqtime、FinalBuilder、IntraWeb和Indy 的64位版本。 TeeChart、Indy和FinalBuilder还支持Mac平台; C++Builder XE2中还包含了新的代码审计和QA度量工具; LiveBindings使用户能连接任意类型的信息到任意的FireMonkey用户界面和图形对象上。用户可以绑定实时数据到标准的用户界面控件、高清或3D图形元素上,以创建可视化任意类型数据的崭新方式; RadPHP: 集成式为移动优化的Web开发; 部署应用到Web, iOS, 或安卓; 扩展的Zend框架组件集; Embarcadero Prism: 来自RemObjects的全新的.NET Oxygene编译器; 匿名接口实现; FastReport.net

64,683

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧