二、爬虫 - 新浪爱问共享资源全下载之功能实现

其实有了爬取的解决方案,用什么语言实现都是可以的,针对这个网站资源特性,根本就不用下载网页,解析网页也就免了,数据的保存也省了,就直接的发送请求,响应请求,之后对链接进行处理(有可能对链接进行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一下的资源,可以下的,如下图的"用手机下载",点下试试就知道了,程序里也是小小的改动下,就可以了,真正免积分我还是知道怎么做,这个么,你懂得意思意思,可以给你个解决方案,大方点的可以程序奉上 大笑



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值