序
其实有了爬取的解决方案,用什么语言实现都是可以的,针对这个网站资源特性,根本就不用下载网页,解析网页也就免了,数据的保存也省了,就直接的发送请求,响应请求,之后对链接进行处理(有可能对链接进行url编码解码)就行了,最后就是下载了,至于下载这一环节,可以采用多线程单线程都可以,因为资源普遍在0~20m左右,多线程显得有点浪费,我这里就采用单线程了。
程序设计
针对资源的特性及分析(参考第一篇)我们只需要有一个整形数据加一个链接(这里分后"http://ishare.iask.sina.com.cn/download.php?fileid=")构造一个请求
资源的url(假如:"http://ishare.iask.sina.com.cn/download.php?fileid=62934995");这样就写一个循环从一个数字增长到另一个数字,直到把数字范围内的链接请求完,整个资源也就下载完了
部分核心代码(C++/MFC)
#define SINA_AIWEN_DOWN_REFER _T("http://ishare.iask.sina.com.cn/download/explain.php?fileid=")
#define SINA_AIWEN_DOWN_LOCATION _T("http://ishare.iask.sina.com.cn/download.php?fileid=")
void CSinaSourceDown::ThreadFun()
{
while(true)
{
// 分配请求链接数据区段
if (m_pWnd != NULL && IsWindow(m_pWnd->m_hWnd))
{
CSinaShareDlg* pDlg = (CSinaShareDlg*)m_pWnd;
if (pDlg->m_dEndValue > _tcstod(pDlg->m_sEnd,NULL))
{
Notify(5,_T("线程结束"));
return;
}
if (HANDLE_IS_VALID(pDlg->m_hMutxAssign))
{
Notify(5,_T("等待分配下载链接"));
DWORD dw = WaitForSingleObject(pDlg->m_hMutxAssign, INFINITE);
if(WAIT_OBJECT_0 == dw)
{
m_tUrlInfor.m_dStartValue = pDlg->m_dEndValue;
m_tUrlInfor.m_nRange = pDlg->m_nAssignRange;
if (m_tUrlInfor.m_dStartValue + m_tUrlInfor.m_nRange > _tcstod(pDlg->m_sEnd,NULL))
{
m_tUrlInfor.m_nRange = (int)(_tcstod(pDlg->m_sEnd,NULL) - m_tUrlInfor.m_dStartValue);
}
pDlg->m_dEndValue = m_tUrlInfor.m_dStartValue + m_tUrlInfor.m_nRange;
ReleaseMutex(pDlg->m_hMutxAssign);
}
}
}
else
{
Notify(5,_T("线程异常结束"));
return;
}
TCHAR* psUrlRefer = SINA_AIWEN_DOWN_REFER;
TCHAR* psUrl = SINA_AIWEN_DOWN_LOCATION;
//while (true)
//{
double dStartValue = m_tUrlInfor.m_dStartValue;
if (dStartValue > 0 && m_tUrlInfor.m_nRange > 0)
{
CString sDownUrl;
CString sLocation;
sLocation = _T("");
CString sReferer;
sReferer = _T("");
CString sTmp ;
sTmp.Format(_T("%d"),m_tUrlInfor.m_nRange);
Notify(2,sTmp);
int nLost = 0;
for (int n = 0; n < m_tUrlInfor.m_nRange; n++)
{
Notify(1,_T("FINDING"));
sTmp.Format(_T("%d"),n+1);
Notify(3,sTmp);
sTmp.Format(_T("%.lf"),dStartValue);
Notify(6,sTmp);
// 构造请求链接
sLocation.Format(_T("%s%.lf"),psUrl,dStartValue);
int i = 0;
sReferer.Format(_T("%s%.lf"),psUrlRefer,dStartValue);
while(1)
{
bool bGet;
if (i == 0)
{
bGet = false;
Notify(5,_T("POST"));
// 初始化请求数据
if(Init(sLocation,bGet,sReferer))
{
// 发送请求
if(Start())
{
int nStat = GetServerState();
if (nStat == 302)
{ // 跳转
Notify(5,_T("REFER LOACTION1"));
GetField(_T("Location"),sLocation);
if (sLocation.IsEmpty())
{
break;
}
}
else if (nStat == 200)
{ // 请求成功 ,记录下载链接
if (i > 0)
{
sDownUrl = sLocation;
}
else
{
Notify(5,_T("LOST"));
sDownUrl = _T("");
}
break;
}
else
{
if (i > 0)
{
sDownUrl = sLocation;
}
else
{
Notify(5,_T("LOST"));
sDownUrl = _T("");
}
break;
}
}
CloseSocket();
}
}
else
{
Notify(5,_T("Get"));
bGet = true;
if(Init(sLocation,bGet))
{
if(Start())
{
int nStat = GetServerState();
if (nStat == 302)
{
Notify(5,_T("REFER LOACTION2"));
GetField(_T("Location"),sLocation);
}
else if (nStat == 200)
{
if (i > 0)
{
sDownUrl = sLocation;
}
else
{
Notify(5,_T("LOST"));
sDownUrl = _T("");
}
break;
}
else
{
if (i > 0)
{
sDownUrl = sLocation;
}
else
{
Notify(5,_T("LOST"));
sDownUrl = _T("");
}
break;
}
}
CloseSocket();
}
}
i++;
}
CloseSocket();
if (!sDownUrl.IsEmpty())
{
// 下载数据
if(!WriteData(sDownUrl))
{
nLost++;
sTmp.Format(_T("%d"),nLost);
Notify(4,sTmp);
}
Notify(7,_T(""));
}
else
{
nLost++;
sTmp.Format(_T("%d"),nLost);
Notify(4,sTmp);
}
dStartValue++;
}
Notify(5,_T("THREAD END"));
}
Notify(5,_T("线程结束"));
}
}
上面的代码就是主要的下载代码了,一些请求下载先关的函数,不管在java 还是c++ 还是c#里都有对应的http协议对应的函数库或类库。
这个函数式一个线程函数,也就是说,可以开很多线程分区段去下载,我想你不会真的会用一个线程循环着从0开始下吧,针对电脑的配置,网速的情况,下载的时间段可以选择线程的个数可多可少(举个例子,我的电脑是i7,8G网速10m,晚上12点下载,我开了32个线程也是相当给力的,你就不用考虑服务器的带宽了,肯定比你本地的带宽牛逼,想想32个资源同时下载是个什么心情,一个字,爽呀),但是考虑下自己的硬盘,适当的下载下来玩玩也挺有意思的,听说有人把爱问上的免积分资源下载完了,
好啦就到这了,我也只能帮你们到这了,这么简单的原理,是个编程的都能写出来(小吹了下
),如果想体验下用mfc写的,可以QQ我奥

注明
这个功能是
针对免积分的资源,如果有积分的,我倒可以做,这里就不费舌了,感兴趣,给点小费啥的,我告诉你
,开玩笑的啦,对于5m一下的资源,可以下的,如下图的"用手机下载",点下试试就知道了,程序里也是小小的改动下,就可以了,真正免积分我还是知道怎么做,这个么,你懂得意思意思,可以给你个解决方案,大方点的可以程序奉上

