CHtmlView 获取div的内容

我使用 MFC CHtmlView 类视图打开了目标网页,里面有个div如下,该div内容是通过ajax动态获取的,html源文件是没有内容的,打开网页后,内容已经显示出来了,请教如何获取到该div的内容?

img

参考GPT和自己的思路,你可以使用 IHTMLDocument2 接口来获取 CHtmlView 中的 HTML 文档对象,并通过 getElementById 方法获取指定的 div 元素。

以下是一个示例代码,可以获取名为 block_content 的 div 元素的内容:

// 获取 CHtmlView 中的 HTML 文档对象
IHTMLDocument2* pDoc = NULL;
if (SUCCEEDED(m_pBrowserApp->get_Document((IDispatch**)&pDoc)))
{
    // 获取名为 "block_content" 的 div 元素
    VARIANT varDivID;
    VariantInit(&varDivID);
    varDivID.vt = VT_BSTR;
    varDivID.bstrVal = SysAllocString(L"block_content");
    IDispatch* pDiv = NULL;
    if (SUCCEEDED(pDoc->getElementById(varDivID, &pDiv)))
    {
        // 获取 div 元素的 HTML 内容
        IHTMLElement* pElem = NULL;
        if (SUCCEEDED(pDiv->QueryInterface(IID_IHTMLElement, (void**)&pElem)))
        {
            BSTR bstrHTML;
            if (SUCCEEDED(pElem->get_innerHTML(&bstrHTML)))
            {
                CString strHTML(bstrHTML);
                // 输出 div 元素的内容
                TRACE(_T("div content: %s\n"), strHTML);
                SysFreeString(bstrHTML);
            }
            pElem->Release();
        }
        pDiv->Release();
    }
    VariantClear(&varDivID);
    pDoc->Release();
}

在上面的代码中,m_pBrowserApp 是 CHtmlView 类中的成员变量,用于获取 IWebBrowser2 接口的指针。getElementById 方法可以根据 div 元素的 ID 属性获取元素对象,get_innerHTML 方法可以获取元素的 HTML 内容。

该回答引用ChatGPT

您可以尝试使用IHTMLDocument2接口中的getElementById()方法来获取该div元素的内容。

首先,您需要获取到当前CHtmlView类视图中显示的HTML文档,可以通过以下代码实现:


IHTMLDocument2* pDoc = GetHtmlDocument();

然后,使用getElementById()方法获取div元素,并将其转换为IHTMLElement接口,代码如下:

CComVariant vId(L"block content");
CComPtr<IDispatch> spElemDispatch;
CComPtr<IHTMLElement> spElem;
HRESULT hr = pDoc->getElementById(vId, &spElemDispatch);
if (SUCCEEDED(hr) && spElemDispatch != NULL) {
    hr = spElemDispatch->QueryInterface(IID_IHTMLElement, (void**)&spElem);
}


最后,您可以使用IHTMLElement接口中的get_innerHTML()方法获取该div元素的内容,代码如下:

if (spElem != NULL) {
    CComBSTR bstrInnerHTML;
    spElem->get_innerHTML(&bstrInnerHTML);
    // 使用 bstrInnerHTML 获取 div 元素的内容
}

需要注意的是,该方法获取到的内容是div元素的innerHTML属性,如果div元素的内容是通过JavaScript动态生成的,则可能无法获取到完整的内容。

注册一个回调函数,该函数将在CHtmlView的文档加载完成后被调用,使用OnDocumentComplete()函数来注册这个回调函数。在回调函数中,获取div的IHTMLElement接口指针,然后调用其innerHTML属性,以获取div的内容。下面是一个示例代码,用于获取名为 "myDiv" 的 div 的内容:

void CMyHtmlView::OnDocumentComplete(LPCTSTR lpszURL)
{
   CHtmlView::OnDocumentComplete(lpszURL);
   // 获取文档中的元素
   CComPtr<IHTMLDocument2> spDoc = GetHtmlDocument();
   CComPtr<IDispatch> spDisp;
   CComPtr<IHTMLElement> spElement;

   spDoc->get_all(&spDisp);
   spDisp->QueryInterface(IID_IHTMLElement, (void**)&spElement);

   // 获取指定名称的元素
   CString strElementName = _T("myDiv");
   CComVariant varName = strElementName.AllocSysString();
   CComPtr<IDispatch> spDisp2;
   spElement->get_elementsByName(varName, &spDisp2);
   CComPtr<IHTMLElementCollection> spCollection;
   spDisp2->QueryInterface(IID_IHTMLElementCollection, (void**)&spCollection);

   // 获取指定名称的元素中的第一个元素
   long lCount = 0;
   spCollection->get_length(&lCount);
   if (lCount > 0)
   {
      CComVariant varIndex((long)0);
      CComPtr<IDispatch> spDisp3;
      spCollection->item(varIndex, varIndex, &spDisp3);
      CComPtr<IHTMLElement> spElement2;
      spDisp3->QueryInterface(IID_IHTMLElement, (void**)&spElement2);

      // 获取元素的 innerHTML 属性
      CComBSTR bstrHTML;
      spElement2->get_innerHTML(&bstrHTML);

      // 将 innerHTML 转换为 CString
      CString strHTML(bstrHTML);
      TRACE(_T("myDiv contents: %s\n"), strHTML);
   }
}

1 获取CHtmlView的文档对象
要获取CHtmlView的文档对象,您可以使用CHtmlView::GetHtmlDocument()方法。此方法返回一个CDocument对象指针,该对象表示当前HTML文档。

CDocument* pDoc = GetHtmlDocument();


2 获取DIV元素对象
要获取指定的DIV元素对象,您可以使用CDocument::GetElementById()方法。此方法需要一个参数,即DIV元素的ID属性值。如果找到了具有指定ID的元素,该方法将返回一个CElement对象指针,否则返回NULL。

CElement* pDivElem = pDoc->GetElementById(_T("div_id"));


3 获取DIV元素的内容
如果找到了指定ID的DIV元素,您可以通过访问CElement对象的innerHTML属性获取其内容。innerHTML属性是一个CComBSTR对象,它表示DIV元素的HTML内容。

if (pDivElem != NULL)
{
    CComBSTR bstrContent;
    pDivElem->get_innerHTML(&bstrContent);
    
    // 将CComBSTR转换为CString
    CString strContent = CString(bstrContent);
}


完成这些步骤后,您将获得指定DIV元素的HTML内容。请注意,如果DIV元素包含子元素,innerHTML属性将返回包括所有子元素的完整HTML代码。如果您只需要DIV元素的文本内容,您可以使用CElement::GetInnerText()方法获取其文本内容。

以下答案基于ChatGPT与GISer Liu编写:
您可以使用 CHtmlView 类的 Navigate 方法来加载网页,并在网页加载完成后获取 div 内容。具体步骤如下:

  1. 在 CHtmlView 的 OnNavigateComplete2 方法中,使用 GetHtmlDocument 方法获取网页的 HTML 文档对象。

  2. 使用该 HTML 文档对象的 GetElementById 方法获取目标 div 对象。

  3. 使用该目标 div 对象的 innerHTML 属性获取 div 内容。

以下是一个完整的 MFC 代码示例,可以打开目标网页并获取指定 div 内容:

// MyHtmlView.h

class MyHtmlView : public CHtmlView
{
public:
    virtual void OnNavigateComplete2(LPCTSTR strURL);
};

// MyHtmlView.cpp

#include "stdafx.h"
#include "MyHtmlView.h"

void MyHtmlView::OnNavigateComplete2(LPCTSTR strURL)
{
    CHtmlView::OnNavigateComplete2(strURL);

    // 获取 HTML 文档对象
    CComPtr<IHTMLDocument2> spDoc = GetHtmlDocument();
    if (!spDoc)
        return;

    // 获取目标 div 对象
    CComPtr<IHTMLElement> spDiv;
    spDoc->getElementById(L"target_div", &spDiv);
    if (!spDiv)
        return;

    // 获取 div 内容
    CComBSTR bstrHtml;
    spDiv->get_innerHTML(&bstrHtml);

    // 将内容转换为 CString 类型并输出
    CString strHtml(bstrHtml);
    AfxMessageBox(strHtml);
}

上述代码中的 “target_div” 是您要获取的目标 div 元素的 ID,您需要将其替换为实际的 ID。

仅供参考:
可以通过CHtmlView的成员函数ExecWB来执行JavaScript代码获取该div的内容。具体步骤如下:

1.在 CHtmlView 派生类的头文件中添加以下声明:

void OnDocumentComplete(LPCTSTR lpszURL);

2.在 CHtmlView 派生类的实现文件中添加以下代码:

void CHtmlViewDerived::OnDocumentComplete(LPCTSTR lpszURL)
{
    CHtmlView::OnDocumentComplete(lpszURL);
    if (lpszURL != NULL)
    {
        CString strScript;
        strScript.Format(_T("var divContent = document.getElementsByClassName('block_content')[0].innerHTML; window.external.GetDivContent(divContent);"));
        ExecWB(OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
        ExecWB(OLECMDID_SCRIPT, OLECMDEXECOPT_DONTPROMPTUSER, &strScript, NULL);
    }
}

void CHtmlViewDerived::GetDivContent(LPCTSTR lpszContent)
{
    CString strContent(lpszContent);
    // TODO: 处理获取到的内容
}

在 OnDocumentComplete 中,首先获取该div的内容的JavaScript代码存放在 strScript 变量中,然后调用 ExecWB 函数执行该代码。该函数的第一个参数是 OLECMDID_SCRIPT,表示执行JavaScript代码,第二个参数是 OLECMDEXECOPT_DONTPROMPTUSER,表示执行代码时不提示用户。第三个参数是 JavaScript 代码,第四个参数是输出参数,表示执行结果,我们不需要使用该参数。

在 JavaScript 代码中,我们首先通过 document.getElementsByClassName('block_content')[0] 获取到该 div 的节点对象,然后通过 innerHTML 获取到该 div 的内容。最后,我们调用外部程序的 GetDivContent 函数,将获取到的内容作为参数传递过去。

GetDivContent 是外部程序的一个函数,用于接收获取到的 div 内容。在该函数中,我们可以对获取到的内容进行处理。