难题!500 分!关于下载网页的问题,_____有好建议或关心者皆有分

SGUav 2003-04-04 11:47:53

我的一个程序中需要获得网页的 html 代码,在程序的第一版中我采用的是 WinInet API 来实现的。第二版我决定采用更加方便可靠的方式。于是选择了 URLDownloadToFile()这个函数,具体是在 http://www.codetools.com/internet/urldownload.asp 提供的方法上进行了一定的改进。

但目前出现的问题是,该方法不适用于 Sina 以及 Sohu 等少数网站。我依稀记得大概在一年前该方法用于 Sina 及 Sohu 一点问题都没有。

所以现在正在严重迷惑中?
...全文
119 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
withoutway 2003-04-30
  • 打赏
  • 举报
回复
用tear的方法不行吗?
winphoenix 2003-04-06
  • 打赏
  • 举报
回复
upup
SGUav 2003-04-06
  • 打赏
  • 举报
回复

感谢 huangbeyond(校园人渣) 和 hktl(風)

我的程序已经基本成型了,可是现在出现了 UrlDownloadToFile() 不能适用于 Sina 等的情况。尽管UrlDownloadToFile() 的功能已经封装到一个类当中去了,但要用其他方法来替换这个类毕竟还是要花一点功夫,所以我只想找一个比较简单的方法重新来实现下载网页的任务,毕竟程序还没写完,拖得太久影响进度。另外下载网页是我的程序必不可少的一个步骤,但程序的核心在于 html 代码的分析。


我的技术验证程序, MFC WinInet 的:

m_EditSourceCode:存储下载的网页html 代码的CString变量
m_EditUrl:存储网页地址的 CString 变量




void CTryWininetDlg::OnBtonDown()
{
UpdateData(TRUE);

//assumes server, port, and URL names have been initialized

CInternetSession session("My Session");
// 开始 HTTP 会话。创建 CInternetSession 对象。初始化 WinInet 并连接到服务器。
CHttpConnection* pServer = NULL;
CHttpFile* pFile = NULL;

DWORD dwRet;
char szBuff[1024];

CString strServerName;
CString strObject;
INTERNET_PORT nPort;
DWORD dwServiceType;

CString strHead;

const TCHAR szHeaders[] =
_T("Accept: text/*\r\nUser-Agent: MFC_Tear_Sample\r\n");


try
{
CString strServerName;
INTERNET_PORT nPort;

if (!AfxParseURL(m_EditUrl, dwServiceType, strServerName, strObject, nPort) ||
dwServiceType != INTERNET_SERVICE_HTTP)
{
MessageBox("Error: can only use URLs beginning with http://");
}

pServer = session.GetHttpConnection(strServerName, nPort); // 连接到 HTTP 服务器。

pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET, strObject);
// 打开 HTTP 请求。
// 发送 HTTP 请求。
pFile->AddRequestHeaders(szHeaders);
pFile->SendRequest();


pFile->QueryInfoStatusCode(dwRet);

if (dwRet == HTTP_STATUS_OK)
{

pFile -> QueryInfo(HTTP_QUERY_CONTENT_LENGTH, strHead); // 通过查询 http 返回的信息获得网页文件大小



UINT nRead = pFile->Read(szBuff, 1023); // 从文件中读取。
while (nRead > 0)
{
nRead = pFile->Read(szBuff, 1023);
m_EditSourceCode += _T(szBuff);

}
}
delete pFile;
delete pServer;
}

catch (CInternetException* pEx) // 处理异常。
{
//catch errors from WinInet
}

session.Close(); // 结束 HTTP 会话。自动清理打开的文件句柄和连接。

UpdateData(FALSE);

}



SGUav 2003-04-06
  • 打赏
  • 举报
回复

to hktl(風) :

呵呵,这些我都试过了,sina 里的任何一个页面或文件都不能用 http://www.codetools.com/internet/urldownload.asp 中提供的 UrlDownloadToFile()来下载,新华网也是如此,而且我还记得比较清楚,大概几个月前该方法用于新华网是毫无问题的。所以肯定这些网站新近采用了什么技术。

但奇怪的是 UrlDownloadToFile()是调用 IE 来工作的,直接用 IE 或 IE 控件就不会出现任何问题。

hktl 2003-04-06
  • 打赏
  • 举报
回复
下载http://www.sina.com.cn/试试
不要index.htm
因为不是所有的主页都是index.htm
各自的服务器可以设置各自的主页
另多使用pFile -> QueryInfo查看http对请求的回复
在下载不到网页里
可以从这里知道原因所在
hktl 2003-04-06
  • 打赏
  • 举报
回复
下载过程一定要开新线程
不然得等下载完才有反响
(常识)

另外由于开多了线程变成是多线程程序
所以你得记得在一些地方同步
hktl 2003-04-06
  • 打赏
  • 举报
回复
刚写错了是socket 不是cosket

SS15(8K99)
反映当前下载进度的方法太多了
最简单的是用一个
至于文件的总字节。你可以在Http回复时得到
然后在程序中每隔一段时间检查一次变量(记录已经下载的字节)

我写过多线程的文件下载工具。
支持http ftp
都是直接用socket实现的。。

如果你的程序以下载为核心
还是用socket实现好
huangbeyond 2003-04-06
  • 打赏
  • 举报
回复
to SS15(8K99)

无意中找到一点资料,希望对你有点帮助.lucky!





使用MSHTML分析HTML代码

--------------------------------------------------------------------------------

发布者:soarlove 发布日期:2002.09.07 升级次数:0 今日/总浏览: 1/455


原作者:Asher Kobin

环境:Windows 2000 / Windows ME / IE 5.0+

我有很多在程序中使用MSHTML的经验,并经常涉及到怎样使用MSHTML来分析HTML代码并通过DOM来访问的问题。

这里给出一个例子,我使用了MSHTML提供的IMarkupServices接口。不需要IOleClientSite或其他任何的嵌入式操作。它可以尽可能简单的获得你所需要的东西。

以后的文章,我将集中的介绍在程序中使用另外的MSHTML使用方法,比如使用MSHTML作为一个编辑器。

这段代码只使用了简单的COM调用。它可以很容易的使用在ATL、MFC、VB和其他的一些语言中。请不要向我要其他语言的例子。如果你需要做的话,你需要IE SDK。

/******************************************************************
* ParseHTML.cpp
*
* ParseHTML: Lightweight UI-less HTML parser using MSHTML
*
* Note: This is for accessing the DOM only. No image download,
* script execution, etc...
*
* 8 June 2001 - Asher Kobin (asherk@pobox.com)
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
* OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
* FITNESS FOR A PARTICULAR PURPOSE.
*
*******************************************************************/

#include <windows.h>
#include <mshtml.h>

OLECHAR szHTML[] = OLESTR("<HTML><BODY>Hello World!</BODY></HTML>");

int __stdcall WinMain(HINSTANCE hInst,
HINSTANCE hPrev,
LPSTR lpCmdLine,
int nShowCmd)
{
IHTMLDocument2 *pDoc = NULL;

CoInitialize(NULL);

CoCreateInstance(CLSID_HTMLDocument,
NULL,
CLSCTX_INPROC_SERVER,
IID_IHTMLDocument2,
(LPVOID *) &pDoc);

if (pDoc)
{
IPersistStreamInit *pPersist = NULL;

pDoc->QueryInterface(IID_IPersistStreamInit,
(LPVOID *) &pPersist);

if (pPersist)
{
IMarkupServices *pMS = NULL;

pPersist->InitNew();
pPersist->Release();

pDoc->QueryInterface(IID_IMarkupServices,
(LPVOID *) &pMS);

if (pMS)
{
IMarkupContainer *pMC = NULL;
IMarkupPointer *pMkStart = NULL;
IMarkupPointer *pMkFinish = NULL;

pMS->CreateMarkupPointer(&pMkStart);
pMS->CreateMarkupPointer(&pMkFinish);

pMS->ParseString(szHTML,
0,
&pMC,
pMkStart,
pMkFinish);

if (pMC)
{
IHTMLDocument2 *pNewDoc = NULL;

pMC->QueryInterface(IID_IHTMLDocument,
(LPVOID *) &pNewDoc);

if (pNewDoc)
{
// do anything with pNewDoc, in this case
// get the body innerText.

IHTMLElement *pBody;
pNewDoc-gt;get_body(&pBody);

if (pBody)
{
BSTR strText;

pBody->get_innerText(&strText);
pBody->Release();

SysFreeString(strText);
}

pNewDoc->Release();
}

pMC->Release();
}

if (pMkStart)
pMkStart->Release();

if (pMkFinish)
pMkFinish->Release();

pMS->Release();
}
}

pDoc->Release();
}

CoUninitialize();

return TRUE;
}
发布者: soarlove

huangbeyond 2003-04-05
  • 打赏
  • 举报
回复
1.我试过了,使用http://www.sina.com.cn/index.html 来下载,
是可以获得该HTML文件的。

2。如果不能确定该HTML文件的具体URL,那么,
可以尝试使用WebControl 来获得HTML代码。
SGUav 2003-04-05
  • 打赏
  • 举报
回复

to huangbeyond(校园人渣):

我在第一版当中用的就是 WinInet API 的方法。但是我没找到用于反映当前下载进度的方法,所以在第二版的程序中改用了URLDownloadToFile(), 用它最大的好处是不仅仅可以用在http:// 还可以用在 file:// ,这样就给我的离线调试带来了极大的方便,另外用它来实现超时控制也十分简单。我到 Codeproject 去看了,也许是网站服务器端安装有防火墙导致URLDownloadToFile()不能正常工作。我也在那的论坛里发帖问了,但目前还没有回答。


to prettywolf:

今天早上好好翻了下 MSDN ,看了例子 tear,我现在写的一个技术验证程序和你的比较类似。

其实还有一个问题大家没注意到,不管用 MFC 的 WinInet 类还是 WinInet API 还是 URLDownloadToFile(),在下载过程中程序都会暂时失去响应,我的解决办法是新开一个线程,把下载的工作放到辅助线程当中去。


用MFC 的 WinInet 类超时的问题我给忘了,看来得要使用信号量 WaitForMultipleObjects() 一类的方法来实现了。

hktl 2003-04-05
  • 打赏
  • 举报
回复
其实自己用cosket下载并不那么复杂
最少我觉得自由度很高
特别是你需要高效率的时候
huangbeyond 2003-04-05
  • 打赏
  • 举报
回复
to: SS15 (8K99)

还有一个稍微麻烦些的办法,就是:
自己使用WinsockAPI,来直接使用HTTP协议,获得URL的内容.

我下http://www.sina.com.cn/index.html ,用的是网络蚂蚁,
它就是这样做的.不要使用那些高度集成的东西,比如CInternetSession或者URLDownloadToFile之类的技术.
sunyard 2003-04-05
  • 打赏
  • 举报
回复
感觉代码有点问题pHttpFile->Read是会抛出异常的,代码里并没有处理,此外,我没有用过这个函数,不知道它处理timeout会不会有问题。URLDownloadToFile就没有这些问题
huanghe99 2003-04-05
  • 打赏
  • 举报
回复
lilylovey 2003-04-05
  • 打赏
  • 举报
回复
收藏!
withoutway 2003-04-05
  • 打赏
  • 举报
回复
好,加分呀!
kbb 2003-04-05
  • 打赏
  • 举报
回复
shaolunyuan 2003-04-05
  • 打赏
  • 举报
回复
蹭分!
prettywolf 2003-04-05
  • 打赏
  • 举报
回复
你贴下来作为一个函数来使用就可以了。
用的是MFC类,十分稳定。
prettywolf 2003-04-05
  • 打赏
  • 举报
回复
我的这段代码经测试过,绝对可以,只要两个参数就可以完成。
网页路径,保存路径。
BOOL CDownLoadDlg::GetFromWeb(LPSTR pURL, LPSTR SaveAsFilePath)
{
CInternetSession session; //会话期对象)

CHttpConnection* pServer = NULL; // 指向服务器地址(URL)

CHttpFile * pHttpFile = NULL;//HTTP文件指针

CString strServerName; //服务器名

CString strObject; //查询对象名(http文件)

INTERNET_PORT nPort; //端口

DWORD dwServiceType; //服务类型

DWORD dwHttpRequestFlags = //请求标志

//INTERNET_FLAG_EXISTING_CONNECT;

INTERNET_FLAG_NO_AUTO_REDIRECT;

const TCHAR szHeaders[]=_T("Accept: text/*\r\nUser-Agent:HttpClient\r\n");

BOOL OK=AfxParseURL( //词法分析

pURL, //被分析URL串

dwServiceType, //服务类型,ftp,http等

strServerName, //服务器名

strObject, //URL中被查询对象

nPort ); //URL指定的端口,可能为空

OK=OK && //本例只考虑http协议

(dwServiceType ==

INTERNET_SERVICE_HTTP);

if (!OK)

{ AfxMessageBox("URL出错"); //报错

return false;

}

pServer = session.GetHttpConnection(strServerName, nPort); //获得服务器名

pHttpFile = pServer-> OpenRequest( CHttpConnection::HTTP_VERB_GET,strObject, NULL, 1, NULL, NULL,dwHttpRequestFlags);

//向服务器发送请求,建立http连接,

//建立本机上的http文件指针

pHttpFile->AddRequestHeaders(szHeaders);

pHttpFile->SendRequest(); //发送请求

CStdioFile f; //输出文件对象

if( !f.Open( //打开输出文件

SaveAsFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary ) )

{ MessageBox("Unable to open file");

return false;

}

//下面将检索结果保存到文件上

TCHAR szBuf[1024]; //缓存
int length=0;
long a=pHttpFile->GetLength();
while (length=pHttpFile->Read(szBuf, 1023))

f.Write(szBuf,length);

f.Close(); //善后工作

pHttpFile ->Close();

pServer ->Close();

if (pHttpFile != NULL) delete pHttpFile;

if (pServer != NULL) delete pServer;

session.Close();

return true;


}
加载更多回复(2)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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