怎么使用MSHTML提取网页上的所有元素,以NODE树的形式显示出来
最好能给点现成源码,谢谢

解决方案 »

  1.   

    // 打开网页
    bool CDomTreeDlg::fProcessDOM(void)
    {
    UpdateData(TRUE);
    //取得网页内容
    IWebBrowser2* pWebBrowser = NULL;
    HRESULT hr = CoCreateInstance(CLSID_InternetExplorer,NULL,CLSCTX_LOCAL_SERVER,IID_IWebBrowser2,(void**)&pWebBrowser ); if( FAILED(hr) )
    {
    AfxMessageBox("WebBrowser2接口失败");
    return FALSE;
    } CComVariant varUrl( m_domURL.GetBuffer(255));
    CComVariant var; hr = pWebBrowser->Navigate2( &varUrl,&var,&var,&var,&var ); // 打开网页
    if( FAILED(hr) ) return FALSE; READYSTATE readystate; 
    hr = pWebBrowser->get_ReadyState(&readystate); // 查询组建状态
    if( FAILED( hr ) ) return FALSE; while( READYSTATE_COMPLETE != readystate ) // 网页下载,完成后等待循环结束
    {
    Sleep(50);
    pWebBrowser->get_ReadyState(&readystate);
    } CComPtr<IDispatch>pDisp; // COM组件的调度接口
    pWebBrowser->get_Document( &pDisp ); // 获得自动化文档对象
    CComQIPtr< IHTMLDocument2 >pDoc2( pDisp ); // 此接口获取HTML文件的信息,并审查和修改HTML元素和文本。
    PrepareDOMTree(pDoc2);
    return TRUE;
    }// 构建DOM树的准备工作
    bool CDomTreeDlg::PrepareDOMTree(CComQIPtr<IHTMLDocument2> pDoc)
    {
    CComQIPtr<IHTMLDocument3> spDoc3 = pDoc; // 此接口提供文件对象的额外的属性和方法。
    bool bRet = spDoc3 != NULL;
    if( !bRet ){
    ATLASSERT(0);
    return bRet;
    }
    CComPtr <IHTMLElement> spRootElement; // 此接口提供了访问所有元素对象共同的属性和方法的能力
    bRet = SUCCEEDED( spDoc3-> get_documentElement( &spRootElement));
    if( !bRet ) return bRet; CComQIPtr <IHTMLDOMNode> spRootNode = spRootElement; // 此接口提供方法来访问所有在文档对象模型(DOM)中的节点
    bRet = spRootNode != NULL;
    if ( !bRet ) return bRet; std::queue<HTREEITEM> queue_tree_nodes; // 存储树形控件的每个节点的句柄
    std::queue<CComQIPtr<IHTMLDOMNode>> queue_DOMNodes; // 存储DOM节点
    queue_tree_nodes.push(TVI_ROOT);
    queue_DOMNodes .push(spRootNode);
    while( !queue_tree_nodes.empty())
    {
    CComQIPtr<IHTMLDOMNode> spDOMNode = queue_DOMNodes.front(); // 提取表的前端
    HTREEITEM parent = queue_tree_nodes.front ();
    queue_DOMNodes.pop();
    queue_tree_nodes.pop(); 
    HTREEITEM thisnode = InsertDOMNode(spDOMNode, parent); // 向树中插入一个DOM节点
    CComPtr<IDispatch> spCollectionDispatch; // COM组件的调度接口
    if ( SUCCEEDED( spDOMNode->get_childNodes( & spCollectionDispatch)))
    {
    long numChildren = 0;
    // 该接口提供方法来存取子节点的集合。
    CComQIPtr<IHTMLDOMChildrenCollection> spCollection = spCollectionDispatch;
    if (NULL != spCollection)
    {
    spCollection->get_length( & numChildren); // 获取集合中子节点的个数
    for ( long i = 0; i < numChildren; i++)
    {
    CComPtr<IDispatch> spItemDispatch;
    spCollection->item( i , &spItemDispatch); // 获取指定索引位置的子节点
    if (NULL != spItemDispatch)
    {
    CComQIPtr<IHTMLDOMNode> spItemNode = spItemDispatch;
    if (NULL != spItemNode)
    {
    queue_DOMNodes.push(spItemNode); // DOM节点放入容器
    queue_tree_nodes.push(thisnode); // 树的节点类型放入容器
    }
    }
    }
    }
    }
    }
    return bRet; // 返回操作是否完成
    }
    // 向树中插入一个DOM节点
    HTREEITEM CDomTreeDlg::InsertDOMNode(IHTMLDOMNode* pINode, HTREEITEM hparent)
    {
    //CComPtr<IDispatch> spCollectionDispatch;
    CComPtr<IHTMLDOMNode> spNode(pINode);
    CComBSTR NodeName; // 标准BSTR是一个有长度前缀和null结束符的OLECHAR数组
    TV_INSERTSTRUCT tvis; // 该结构包含添加新项到树形视控件所使用的信息
    tvis.hParent = hparent; // 父项的句柄
    tvis.hInsertAfter = TVI_LAST; // 插入的新项之后的项的句柄=在列表的最后插入项
    tvis.item.mask =  TVIF_TEXT | TVIF_PARAM; // 设置树结构成员有效性屏蔽位
    if ( SUCCEEDED( spNode->get_nodeName( & NodeName)))
    {
    CString strNodeName( NodeName); // !这里是标签名字
    tvis.item.pszText= _strdup(strNodeName); // 复制字符串s:char *strdup(char *s);
    }   
    // 需要AddRef因为我们将会保持接口指针作为treeview的数据项
    pINode->AddRef(); // COM组件增加引用计数
    tvis.item.lParam = reinterpret_cast<LPARAM>(pINode); // 消息的发送者传递结构的指针
    HTREEITEM hthisItem = m_domTree.InsertItem( &tvis ); // 插入一个树项
    if ( hthisItem == NULL)
    {
    pINode->Release(); // COM组件减少引用计数
    return NULL;
    }
    return hthisItem;
    }