采集网页选定部分全攻略

王朝vc·作者佚名  2006-01-17
宽屏版  字体: |||超大  

采集网页选定部分全攻略

作者:龙仪

下载源代码

在 VCKBASE 混了这么久竟然没有写出一篇文章,想想很是惭愧,每当在这里看到一篇好文,这种感觉尤甚,总结我在程序员加油站中的一些技术点写了这个文章(虽然程序员加油站还要继续开发,但是由于时间关系不知道什么时候能完成),如果有时间我还会写一些文章的,我的写作水平可能很差,希望读者能够包涵。

程序原理:

一、在IE菜单中加入菜单项

在注册表HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt项下建立一个新项,项的名称即为出现在菜单中的标题

将新建项的默认值设定为一个URL地址,当用户点击菜单项后,IE就会调用URL指向的页面中的脚本。

二、如何控制菜单项在合适的时候显示

下面再介绍一下上面注册项中Contexts项的作用,通过该项可以制定菜单项在右键点击IE中的什么对象时出现,它可以为以下值的“或”组合

对象

缺省

0x1

图片

0x2

控件

0x4

表单域

0x8

选择文本

0x10

锚点

0x20

超链接

0x22

例如上面我们希望菜单项在用户点击图片或者超链接时出现,那么我们就将值设置为dword:00000022

既在点击图片 或者 锚点时出现菜单。一个锚点是页面中描述一个超链接的对象。如果不设置Contexts

项,则菜单项会在点击任何对象时出现在右键菜单中。

注:

一二部分我引用了《如何在IE右键菜单中添加菜单项以及如何添加IE任务栏按钮》这篇文章的部分内容,详细内容请看:

http://www.csdn.net/develop/read_article.asp?id=3621

三、编辑点击菜单项执行的script脚本

这个脚本的文件名和1中的链接文件一致这个是我用的脚本:

<script language="VBScript"

Sub OnContextMenu()

set nc=CreateObject("Test2.testa.1")

nc.GetHtmlText()

end sub

Call OnContextMenu()

</script

//看到网海拾贝中这样用

<script language="VBScript"

Sub OnContextMenu()

NCWEBPAGE=1

NCSELWEBPAGE=2

NCSELTEXT=3

NCALLTEXT=4

NCIMAGE=5

NCALLIMAGE=6

NCALLLINK=7

NCALLLINKTITLE=8

NCSELSOURCECODE=9

NCSOURCECODE=10

On Error Resume Next

set nc=CreateObject("NcActive.NcCollect")

if err<0 then

MsgBox("网海拾贝没有正确安装")

else

//但是这个参数至今不知道如何在控件中得到

call Nc.Gethtmldoc(NcSelText,external.menuArguments.document)

end if

end sub

Call OnContextMenu()

</script

四、在注册表中加入

HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall

\\程序员加油站加入ArticlePath - 文档存盘路径(string),ArticleNumber -文档序号(dword)。

五、写一个ATL的DLL,就是上面脚本中调用的那个对象,提供一个接口GetHtmlText(),看到有些其他程序使用external.menuArguments.document做为参数,可是我没试验成功,无法直接获得其中的document所以只能用笨方法了,取得当前窗口,然后取得IE子窗口的句柄,然后取得document指针,取得选取的内容,然后保存网页,并下载图片。

下面就介绍一下ATL组件的制作,主要技术包括ATL编程,IE编程,注册表操作。

1,用ATL COM模板创建一个工程

2,加入一个接口testa

3,加入Urlmon.Lib 和 #include <urlmon.h

4,加入接口函数GetHtmlText()

实现如下:

STDMETHODIMP Ctesta::GetHtmlText()

{

//保存网页内容的目录

char chFilePath[MAX_PATH];

DWORD Number = 0;

CRegistry reg;

reg.Open(HKEY_LOCAL_MACHINE,

"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\程序员加油站\\");

BOOL ret = reg.ReadDWORD("ArticleNumber",&Number);

if(!ret)

return S_FALSE;

//读取保存网页文件的目录

ret = reg.ReadString("ArticlePath",chFilePath);

if(!ret)

return S_FALSE;

//取得当前活动窗口的窗口句柄

HWND hWnd = GetActiveWindow();

CoInitialize( NULL );

//显式装载 MSAA 判断是否被安装

HINSTANCE hInst = ::LoadLibrary( _T("OLEACC.DLL") );

if ( hInst != NULL )

{

if ( hWnd != NULL )

{

HWND hWndChild=NULL;

// 取得当前窗口的IE子窗口指针

::EnumChildWindows( hWnd, EnumChildProc, (LPARAM)&hWndChild );

if ( hWndChild )

{

//定义IE文档

CComPtr pHTMLDoc;

LRESULT lRes;

//由于WM_HTML_GETOBJECT非Windows标准消息,所以需要RegisterWindowMessage

UINT nMsg = ::RegisterWindowMessage( _T("WM_HTML_GETOBJECT") );

::SendMessageTimeout( hWndChild, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes );

LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress( hInst, _T("ObjectFromLresult") );

if ( pfObjectFromLresult != NULL )

{

HRESULT hr;

//获取网页的IHTMLDocument2接口

hr = (*pfObjectFromLresult)( lRes, IID_IHTMLDocument, 0, (void**)&pHTMLDoc );

if ( SUCCEEDED(hr) )

{

CComPtr pSelObj;

CComPtr pTxtRange;

//根据IHTMLDocument2指针取得IHTMLSelectionObject接口指针

pHTMLDoc-get_selection(&pSelObj);

//再获得IHTMLTxtRange指针

hr = pSelObj-createRange((IDispatch**)&pTxtRange);

if(!CheckResult(hr,"pTxtRange"))

return hr;

//选择所有被选择的内容

pTxtRange-select();

BSTR bstrTxt,bstrTxt1;

char strPath[MAX_PATH];

char *strTxt = NULL;

char*strTxt1 = NULL;

//取得主站域名

CComPtr pLocation;

pHTMLDoc-get_location(&pLocation);

pLocation-get_hostname(&bstrTxt1);

strTxt1 = _com_util::ConvertBSTRToString(bstrTxt1);

sprintf(strPath,"http://%s",strTxt1);

SaveCharToFile(strTxt1,debugpath);

//取得选中的内容

pTxtRange-get_htmlText(&bstrTxt);

strTxt = _com_util::ConvertBSTRToString(bstrTxt);

//下载内容中的图片资源,并修改相应链接

std::string webpage;

char chSavePath[MAX_PATH];

sprintf(chSavePath,"%s\\T%ld.htm",chFilePath,Number);

CreateAllDirectory(chSavePath);

//取得所有图片资源并保存网页

if(CheckData(strTxt,strPath,chFilePath,Number,webpage) == FALSE)

SaveCharToFile(strTxt,chSavePath,TRUE);

else

SaveCharToFile(webpage.c_str(),chSavePath,TRUE);

BOOL ret = reg.WriteDWORD("ArticleNumber",++Number);

//释放内存

if(strTxt1)

delete[] strTxt1;

if(strTxt)

delete[] strTxt;

SysFreeString(bstrTxt1); // 用完释放

SysFreeString(bstrTxt); // 用完释放

}

}

}

} // else Internet Explorer is not running

::FreeLibrary( hInst );

} // else Active Accessibility is not installed

CoUninitialize();

return S_OK;

}

在取得选取网页内容之后,需要对HTML内容进行重新编辑以获得正确的显示,CheckData函数便是做这个工作的这个函数对HTML内容中图像信息的地址进行编辑,如果图像保存在本地则使用本地图像,如果图像没有下载保持原样。

BOOL CheckData(const LPCTSTR data,

const LPCTSTR host,

const LPCTSTR path,

DWORD Number,

std::string &outstring)

{

char chImgPath[1024];//图像路径 !:由于有些图像路径可能会很长所以申请内存多一点

char chImgSrc[MAX_PATH];//图像地址

char chDownLoadPath[MAX_PATH];//下载图像文件路径

char chWriteImgSrc[MAX_PATH];//图像文件路径

memset(chImgPath,0,1024);

memset(chImgSrc,0,MAX_PATH);

memset(chDownLoadPath,0,MAX_PATH);

memset(chWriteImgSrc,0,MAX_PATH);

char dirname[20];//根目录名

ltoa(Number,dirname,10);

try{

//查找是否有<img标记

const char *p1 = FindString(data,"<img");

const char *p2 = FindString(p1,"src=\"");

const char *p3 = FindString(p2+5,"\"");

const char *p4 = FindString(p1,"");

if(p1 == NULL||p2 == NULL||p3 == NULL||p4 == NULL)

return FALSE;

//找到一个图像文件标记

//拷贝图像链接之前的文字

int n = p4-p1+1;

strncpy(chImgPath,p1,n);

outstring.append(data,p2-data+5);

//提取图像链接

n = p3-p2-5;

strncpy(chImgSrc,p2+5,n);

if(FindString(chImgSrc,"http://") == NULL){

if(FindString(chImgSrc,".."))

strcpy(chImgSrc,&chImgSrc[2]);

sprintf(chDownLoadPath,"%s%s",host,chImgSrc);

sprintf(chWriteImgSrc,"%s//%s%s",path,dirname,chImgSrc);

}else{

strcpy(chDownLoadPath,chImgSrc);

const char *p5 = FindString(chImgSrc+7,"/");

sprintf(chWriteImgSrc,"%s\\%s%s",path,dirname,&chImgSrc[p5-chImgSrc]);

}

char Output[MAX_PATH];

sprintf(Output,"图像地址:%s\r\n存盘地址:%s\r\n主机地址:%s\r\n",chImgSrc,chWriteImgSrc,host);

SaveCharToFile(Output,debugpath);

n = strlen(chWriteImgSrc);

for(int i=0;i<n;i++){

if(chWriteImgSrc[i] == ''''/'''')

chWriteImgSrc[i] = ''''\\'''';

}

//在下载之前先建立保存图像文件的路径

CreateAllDirectory(chWriteImgSrc);

//下载图像文件

HRESULT hr = URLDownloadToFile( NULL, chDownLoadPath, chWriteImgSrc, 0, NULL);

if( SUCCEEDED(hr))//

{

const char *p6 = FindString(chDownLoadPath+7,"/");

sprintf(chWriteImgSrc,"%s%s",dirname,&chDownLoadPath[p6-chDownLoadPath]);

//将存盘的路径保存进字符串

}else{

strcpy(chWriteImgSrc,chDownLoadPath);

//没有下载成功将原始路径保存进

}

outstring.append(chWriteImgSrc);

outstring.append(p3,p4-p3+1);

BOOL ret = CheckData(p4+1,host,path,Number,outstring);

if(!ret){

outstring.append(p4+1);

}

}catch(...){

return FALSE;

}

return TRUE;

}

其他几个辅助函数这里简单介绍,详细内容请参看源代码

函数:void SaveCharToFile

功能:将字符串保存为给定文件名

const LPCTSTR data,//[IN] 给定待保存的数据

const LPCTSTR saveFileName,//[IN]给定文件名

BOOL flag = FALSE//[IN]追加写入还是覆盖标志

函数:const char *FindString

功能:在给定字符串中查找给定字符串

const LPCTSTR source,//[IN] 给定源字符串的数据

const LPCTSTR key)//[IN]待查字符串

函数:void CreateAllDirectory

功能:创建给定路径的所有未建目录

const char* AllPath)//[IN] 需要创建的详细目录

例如 输入为:"d:\a\b\c\d"则在D盘下创建相应a,b,c,d相应目录

好了,到此为止,我们已经做成一个取得网页选取内容的并保存在本地的程序,你可以举一反三,将它应用到更有趣更有用的领域。

这个程序是我研究了一周才写完的,其中取得domument的方法我觉得很笨,可我现在没有找到好办法,希望能够抛砖引玉,有更好的方法别忘了告诉我,我的Email:lgtest@sina.com欢迎来信讨论。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
© 2005- 王朝网络 版权所有