從FireFox中抓取當前網頁內容


FireFox采用Gecko內核,不同於IE內核,不能直接通過HWND像處理IE內核那樣獲取IHTMLDocument2。幸好Mozilla為Gecko做了一層映射,使得Gecko支持MSAA接口,可以通過HWND間接獲得IHTMLDocument2(實際上是ISimpleDOMDocument,和IHTMLDocument2同樣繼承自IUnknown)。

網上有篇文章《基於IE和Gecko內核的網頁內容獲取與分析研究》,可惜這篇文章中提到的方法只對舊版的FireFox有效。搜了好久都沒發現有關新版本的中文資料,許多文章都是針對FireFox3.x,並且不太靠譜。無耐之下只得研究Mozilla官網文檔。

Mozilla官網文章:

Supported MSAA Interfaces》:講了對Gecko做了映射,以支持MSAA接口。

MSAA Implementation Features》:講如何如何獲取網頁文檔信息,但不全是我們想要的,我們要做的是通過HWND的到當前標簽頁的網頁文檔信息。

Find the Window and Load the Document》:告訴我們FireFox將變成一個單窗口的應用程序。最終查找頂層UI窗口並加載網頁文檔(ISimpleDOMDocument)的唯一方法是使用“accessible relation NAVRELATION_EMBEDS”。我使用SPY++查看FireFox9的窗口時確實如此,只有主界面一個窗口,窗口類為MozillaWindowClass。這篇文章修改日期是“20:42, 4 Mar 2008”,因此這個方法在很早的版本中就已經采用了,可是文中資料卻鮮有提及。

MSAA Relations》:定義了上面提到的NAVRELATION_EMBEDS的值。

參考上面三篇文章和其他一些參考資料有了下面獲取網頁文檔的方法:

1、從Mozilla Developer Center下載三個文件ISimpleDOMNode.idl、ISimpleDOMText.idl 、ISimpleDOMDocument.idl,《MSAA Implementation Features》下有提供下載鏈接。

2、使用微軟的IDL編譯器即MIDL(位於VC6安裝目錄下的VC98\Bin中)來生成Windows平台下的頭文件,命令格式如下: 
  MIDL ISimpleDOMNode.idl 
  MIDL ISimpleDOMText.idl 
  MIDL ISimpleDOMDocument.idl

然后我們就得到了9個文件,其中只需要6個:ISimpleDOMNode.h、ISimpleDOMNode_i.c、ISimpleDOMText.h、ISimpleDOMText_i.c、ISimpleDOMDocument.h、ISimpleDOMDocument_i.c

3、假設已經得到到FireFox窗口句柄了,以獲取網頁URL為例,代碼如下:

 

#include <windows.h>
#include <objbase.h>
#include <atlbase.h>
#include <oleacc.h>
#include <comutil.h>

#include "ISimpleDOMNode.h"
#include "ISimpleDOMText.h"
#include "ISimpleDOMDocument.h"

////////////////////////////////////////////////////////////////////////////////
//

// NAVRELATION_EMBEDS 要自己定義,其值在《MSAA Relations》中給出
#ifndef NAVRELATION_EMBEDS
#define NAVRELATION_EMBEDS 0x1009
#endif

////////////////////////////////////////////////////////////////////////////////
//
bool GetUrl_Gecko(HMODULE hOleAccDll, HWND hWndBrowser, LPTSTR pszUrl, size_t stBytes)
{
if (NULL == hOleAccDll || NULL == hWndBrowser)
{
return false;
}

TCHAR szClassName[_MAX_PATH] = {0};
::GetClassName(hWndBrowser, szClassName, sizeof(szClassName));
if (_tcsncmp(szClassName, TEXT("MozillaWindowClass"), sizeof(szClassName)) != 0)
{
return false;
}

IAccessible* pAccBrowser = NULL;

LPFNACCESSIBLEOBJECTFROMWINDOW pfAccessibleObjectFromWindow
= (LPFNACCESSIBLEOBJECTFROMWINDOW)::GetProcAddress(
hOleAccDll, "AccessibleObjectFromWindow");

if (NULL == pfAccessibleObjectFromWindow)
{
return false;
}

HRESULT hr = pfAccessibleObjectFromWindow(
hWndBrowser, OBJID_CLIENT, IID_IAccessible, (void**)&pAccBrowser);
if (FAILED(hr) || NULL == pAccBrowser)
{
return false;
}

VARIANT vtStart;
VARIANT vtResult;

vtStart.vt = VT_I4;
vtResult.lVal = CHILDID_SELF;

pAccBrowser->accNavigate(NAVRELATION_EMBEDS, vtStart, &vtResult);

IDispatch* pDisp = vtResult.pdispVal;
if (NULL == pDisp)
{
return false;
}

IAccessible* pAccDoc = NULL;
hr = pDisp->QueryInterface(IID_IAccessible, (void**)&pAccDoc);
if (FAILED(hr) || NULL == pAccDoc)
{
return false;
}

IServiceProvider *pServProv = NULL;
hr = pAccDoc->QueryInterface(IID_IServiceProvider, (void**)&pServProv);
if (FAILED(hr) || NULL == pServProv)
{
return false;
}

const GUID refguid = {0x0c539790, 0x12e4, 0x11cf, 0xb6, 0x61,
0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};

ISimpleDOMNode* pNode = NULL;
hr = pServProv->QueryService(refguid, IID_ISimpleDOMNode, (void**)&pNode);
if (FAILED(hr) || NULL == pNode)
{
return false;
}

ISimpleDOMDocument* pDoc = NULL;
hr = pNode->QueryInterface(IID_ISimpleDOMDocument, (void**)&pDoc);
if (FAILED(hr) || NULL == pDoc)
{
return false;
}

BSTR bstrUrl = NULL;
hr = pDoc->get_URL(&bstrUrl);
if (FAILED(hr) || NULL == bstrUrl)
{
return false;
}
_tcsncmp(pszUrl, _bstr_t(bstrUrl), stBytes);

return true;
}

////////////////////////////////////////////////////////////////////////////////
//
bool GetWebPageUrl(HWND hWndBrowser, LPTSTR pszUrl, size_t stBytes)
{
if (!::IsWindow(hWndBrowser))
{
return false;
}

::CoInitialize(NULL);

// 顯示加載 MSAA 以便確定是否已安裝
HMODULE hOleAccDll = ::LoadLibrary(TEXT("OLEACC.DLL"));
if (NULL == hOleAccDll)
{
::CoUninitialize();
return false;
}

bool bSucceeded = ::GetUrl_Gecko(hOleAccDll, hWndBrowser, pszUrl, stBytes);

::FreeLibrary(hOleAccDll);
::CoUninitialize();

return bSucceeded;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM