当前位置:   article > 正文

C++ 高性能爬虫

C++ 高性能爬虫
main.cpp
  1. #include "stdafx.h"
  2. #include "CNetCrawler.h"
  3. #include"afxmt.h"
  4. #include"DownloadData.h"
  5. #include"MainThread.h"
  6. #include"ProjectDlg.h"
  7. #include"CNetCrawlerDlg.h"
  8. #include<afxinet.h> //向http服务器发送请求及网络相关操作的头文件
  9. #ifdef _DEBUG
  10. #define new DEBUG_NEW
  11. #undef THIS_FILE
  12. static char THIS_FILE[] = __FILE__;
  13. #endif
  14. extern CCNetCrawlerDlg *pDlg; //主窗口的指针
  15. extern bool ThreadPause; //是否暂停线程
  16. //全局变量
  17. /
  18. // MainThread
  19. IMPLEMENT_DYNCREATE(MainThread, CWinThread)//在类声明中包含了DECLARE_DYNCREATE 允许CObject派生类对象在运行时自动建立
  20. //用户界面线程构造函数
  21. MainThread::MainThread()
  22. { //用户界面线程构造函数
  23. m_bDone=false; //初始化线程未停止
  24. }
  25. MainThread::~MainThread(){
  26. }
  27. //函数功能:初始化
  28. BOOL MainThread::InitInstance(){ //重写初始化函数
  29. // TODO: perform and per-thread initialization here
  30. //生成一个新建工程对话框
  31. //设置共享数据
  32. m_DownData.SetPro(m_FileId,m_ThreadNum,m_LocalDir);//根据用户设定起始文件名称,最大线程数量,保存路径
  33. m_BeginURL.MakeLower();//起始地址的设置
  34. if(m_BeginURL.Find(_T("http://"))==-1)
  35. str_BeginURL=_T("http://")+m_BeginURL;//若初始的URL地址并不是以http://开头,则加入
  36. else str_BeginURL=m_BeginURL; //将初始URL地址赋值给工程起始网络地址变量str_BeginURL
  37. str_ProjectName=m_ProjectName;//工程名的设置
  38. CWnd *button; //窗口类中的按钮
  39. button=pDlg->GetDlgItem(IDC_BUTTON_NEW);//通过子窗口IDC_BUTTON_NEW得到窗口指针
  40. button->EnableWindow(FALSE);//设置该指定的窗口禁止接受鼠标和键盘的输入
  41. Run(str_BeginURL); //运行守护线程,启动工作者线程,下载网页
  42. return TRUE;
  43. }
  44. /*
  45. int MainThread::ExitInstance(){
  46. CWnd *button;
  47. button=pDlg->GetDlgItem(IDC_BUTTON_NEW);
  48. button->EnableWindow(TRUE); //线程结束,设置该指定的窗口允许鼠标和键盘的输入
  49. // TODO: perform any per-thread cleanup here
  50. return CWinThread::ExitInstance();
  51. }
  52. */
  53. int MainThread::ExitInstance(){
  54. CWnd *button;
  55. button=pDlg->GetDlgItem(IDC_BUTTON_NEW);
  56. button->EnableWindow(TRUE); //线程结束,设置该指定的窗口允许鼠标和键盘的输入
  57. ThreadPause=false;
  58. pDlg->m_active=true;//-置回初始值,以便新建下一个工程(7.6添加)
  59. pDlg->m_pause.EnableWindow(false);//-禁用按钮“暂停/继续”,工作日志(四)中有资料。
  60. pDlg->m_stop.EnableWindow(false);//-禁用按钮“停止”,工作日志(四)中有资料。(7.6添加)
  61. // TODO: perform any per-thread cleanup here
  62. return CWinThread::ExitInstance();
  63. }
  64. BEGIN_MESSAGE_MAP(MainThread, CWinThread) //使用宏BEGIN_MESSAGE_MAP实现消息映射
  65. //{{AFX_MSG_MAP(MainThread)
  66. // NOTE - the ClassWizard will add and remove mapping macros here.
  67. //}}AFX_MSG_MAP
  68. END_MESSAGE_MAP() //消息映射结束
  69. /*===========================================全局函数===========================================================*/
  70. /*-----------------------------------------------------------------------------------
  71. 函数功能:从网页中提取URL
  72. 调用之前的预备条件:网页已经从网络上下载到本地存为临时文件
  73. 返回后的处理:删除临时文件
  74. 入口参数:
  75. CString s 临时文件的本地地址
  76. MainThread *ptr 用于获得主控线程的共享数据区
  77. 抽象算法:
  78. ①只读方式打开本地文件
  79. ②查找连接,若未在共享数据区的URL任务队列中出现,则加入队列
  80. ③关闭文件
  81. 调用关系:被每一个工作者线程调用,来从网页中读取链接
  82. 工作者线程(worker thread)的传入函数不能为类中的成员函数,故声明为全局函数
  83. -----------------------------------------------------------------------------------*/
  84. void FindURL(CString s, MainThread *ptr){
  85. CStdioFile fin; //CStdioFile 对象代表一个用运行时函数fopen 打开的C 运行时流式文件
  86. if(!fin.Open(s,CFile::modeRead))
  87. return; //以只读模式打开文件 s是临时文件的本地地址
  88. CString str_BaseURL;
  89. if(!fin.ReadString(str_BaseURL))
  90. return; //从文件读出的字符串为空
  91. CString mark="href="; //-链接以"href="开始
  92. int i=-1,j=-1,URL_end=-1;
  93. CString str_Line,str_URL;
  94. bool exist=false; //-标记网页是否被访问过的标签
  95. while(fin.ReadString(str_Line))
  96. { //-从指定文件中读取一行,读取成功时执行循环
  97. if(ptr->m_DownData.IsFull())
  98. break; //ptr用于控制主线程的数据区
  99. i=str_Line.Find(mark);
  100. if(i==-1)
  101. continue; //如果本行无URL
  102. /*------------------------否则(本行有URL),提取一个链接------------------------*/
  103. //-处理形如"href = "http://..." "的URL
  104. str_Line=str_Line.Mid(i+4); //-去掉herf
  105. str_Line.TrimLeft(); //-去掉当前字符串最左边的空格
  106. if(str_Line[0]=='=')
  107. str_Line=str_Line.Mid(1); //-去掉当前字符串起始的等号(若等号存在)
  108. str_Line.TrimLeft(); //-去掉当前字符串最左边的空格
  109. if(str_Line[0]=='\"') //str_Line[0]是双引号
  110. { //-处理" "中的URL
  111. URL_end=str_Line.Find(_T("\""),1); //找到双引号之间的URL地址
  112. if(URL_end==-1 || URL_end==1)
  113. continue; //并未找到
  114. str_URL=str_Line.Mid(1,URL_end-1); //设置URL的值是从网页中获得链接"href=" (双引号)
  115. }
  116. else if(str_Line[0]=='\'') //str_Line[0]是单引号
  117. { //处理' '中的URL
  118. URL_end=str_Line.Find(_T("\'"),1);
  119. if(URL_end==-1 || URL_end==1)
  120. continue;
  121. str_URL=str_Line.Mid(1,URL_end-1); //设置URL的值是从网页中获得链接"href=" (双引号)
  122. }
  123. else{
  124. i=str_Line.Find(_T(">"));
  125. j=str_Line.Find(_T(" "));
  126. if(i==-1) URL_end=j; //若无>,截至空格
  127. else if(j==-1) URL_end=i; //若无空格,截至>
  128. else if(i>j) URL_end=j; //若都有,且>在空格前出现,截至空格
  129. else URL_end=i; //若都有,且>在空格后出现,截至>
  130. if(URL_end==-1) continue; //i=-1&&j=-1时,进行下一次循环
  131. str_URL=str_Line.Left(URL_end);
  132. }
  133. if(str_URL.Find(_T("mailto:"))!=-1 ) continue; //忽略电子邮件地址
  134. if(str_URL.Find(_T("#"))!=-1 ) continue; //忽略含#的URL
  135. if(str_URL.Find(_T(".asp"))==-1 && str_URL.Find(_T(".php"))==-1 && str_URL.Find(_T(".jsp"))==-1 &&
  136. str_URL.Find(_T(".aspx"))==-1 && str_URL.Find(_T(".htm"))==-1 && str_URL.Find(_T(".html"))==-1 &&
  137. str_URL.Find(_T(".shtml"))==-1 && str_URL.Find(_T(".shtml"))==-1 && str_URL[str_URL.GetLength()-1]!=_T('/')) continue;//忽略掉含以上字符串的URL
  138. /*------------------------用网页中获取的相对地址算出URL------------------------*/
  139. str_URL.TrimLeft(); //-去掉最左边的空格
  140. str_URL.TrimRight(); //-去掉最右边的空格
  141. if(str_URL==_T("")) continue; //若为空,继续
  142. if(str_URL==_T("http://")) continue; //若为http://,继续
  143. if(str_URL.Find(_T("http:"))==-1){
  144. LPTSTR p=new TCHAR[200];
  145. unsigned long m=200;
  146. /*
  147. BOOL InternetCombineUrl(
  148. __in LPCTSTR lpszBaseUrl,
  149. __in LPCTSTR lpszRelativeUrl,
  150. __out LPTSTR lpszBuffer,
  151. __inout LPDWORD lpdwBufferLength,
  152. __in DWORD dwFlags
  153. );
  154. Value
  155. ICU_BROWSER_MODE
  156. Meaning
  157. Does not encode or decode characters after "#" or "?", and does not remove trailing white space after "?".
  158. If this value is not specified, the entire URL is encoded and trailing white space is removed.
  159. http://msdn.microsoft.com/en-us/library/aa384355(VS.85).aspx
  160. //-工作日志(五)中有更多相关资料
  161. */
  162. if(!InternetCombineUrl(str_BaseURL,str_URL,p,&m,ICU_BROWSER_MODE)) continue;//-根据网页中获取的相对地址算出URL,失败则进行下一次循环
  163. str_URL=p;
  164. delete []p;
  165. }
  166. // if(str_URL.Find(ptr->str_Confine)==-1)continue;
  167. if(!(ptr->m_DownData.IsExisted(str_URL))) ptr->m_DownData.AddURL(str_URL);//-若未在共享数据区的URL任务队列中出现,则加入队列
  168. }
  169. fin.Close();//-关闭
  170. }
  171. /*-------------------------------------------------------------------------------------
  172. 函数功能:
  173. // controlling function for the worker thread
  174. // 从URL任务队列得到一个网址并尝试
  175. 调用之前的预备条件:网页已经从网络上下载到本地存为临时文件
  176. 返回后的处理:删除临时文件
  177. 入口参数:
  178. LPVOID pParam 主控线程的指针,用于获取共享数据区
  179. 抽象算法:
  180. ①试图从URL队列中获取一个URL,若失败则返回(结束线程)
  181. ②根据地址向服务器发送请求,若请求失败则返回(结束线程)
  182. ③根据网页,提取主要内容,并存一个临时文件,用FindURL函数查找链接
  183. ④从共享数据区删除线程标签
  184. ⑤结束线程
  185. 工作者线程(worker thread)的传入函数不能为类中的成员函数,故声明为全局函数
  186. -----------------------------------------------------------------------------------*/
  187. UINT DownloadFile(LPVOID pParam){
  188. MainThread *ptr=(MainThread *)pParam; //pParam 主控线程的指针,用于获取共享数据区
  189. CString URL;
  190. if(!(ptr->m_DownData.GetCurURL(URL))){ //试图获取一个URL
  191. ptr->m_DownData.DeleThread();
  192. return 0;
  193. }
  194. //以下为建立网络发出请求
  195. //使用类CInternetSession 创建并初始化一个或多个同时的Internet 会话。如果需要,还可描述与代理服务器的连接。
  196. //如果Internet连接必须在应用过程中保持着,可创建一个类CWinApp的CInternetSession成员。
  197. /*
  198. CInternetSession(
  199. LPCTSTR pstrAgent = NULL,
  200. DWORD_PTR dwContext = 1,
  201. DWORD dwAccessType = PRE_CONFIG_INTERNET_ACCESS,
  202. LPCTSTR pstrProxyName = NULL,
  203. LPCTSTR pstrProxyBypass = NULL,
  204. DWORD dwFlags = 0
  205. );
  206. INTERNET_OPEN_TYPE_DIRECT //Connect directly to Internet.
  207. */
  208. CInternetSession MyConnect(_T("Microsoft MFC APP"),1,INTERNET_OPEN_TYPE_DIRECT);
  209. CHttpConnection* pServer = NULL; //为试图打开连接的应用打开一个HTTP服务器
  210. CHttpFile* pHttpFile=NULL; //CHttpFile提供向HTTP服务器中请求和读取的功能
  211. // check to see if this is a reasonable URL http://210.48.16.168 /ss/aa.jpg
  212. CString strServerName; //210.48.16.168
  213. CString strObject; ///ss/aa.jpg
  214. INTERNET_PORT nPort; //端口
  215. DWORD dwServiceType; //URL的支持类型 如http
  216. try
  217. { //如果成功地解析了URL,则返回非零值。如果URL为空或它不包含已知的Internet服务类型,则为0
  218. if(!AfxParseURL(URL, dwServiceType, strServerName, strObject, nPort) || //dwServiceType返回URL支持的类型
  219. dwServiceType != INTERNET_SERVICE_HTTP)
  220. { //不是http站点
  221. THROW(new CInternetException(dwServiceType)); //除去异常 错误
  222. } //用CInternetSession实例来构造CHttpConnection对象
  223. pServer=MyConnect.GetHttpConnection(strServerName, nPort);//当前的URL向服务器请求,建立连接
  224. pHttpFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET, //得到指向CHttpFile类的指针
  225. strObject, NULL, 1, NULL, NULL);
  226. pHttpFile->AddRequestHeaders(_T("Accept: text/*\r\nUser-Agent: MFC\r\n"));//添加发往HTTP服务器的请求头
  227. pHttpFile->SendRequest(); //向HTTP服务器发送请求
  228. DWORD StatusCode;
  229. pHttpFile->QueryInfoStatusCode(StatusCode);//获得HTTP请求相关联的状态号并将其放到所提供的StatusCode 参数中
  230. //只有在SendRequest 被成功调用或者一个CHttpFile对象被 OpenURL成
  231. //功创建后,才能使用该成员函数
  232. //file isn't there or is redirected
  233. /*200 URL定位,接着传输 400 不可理解的请求 404 所请求的URL未找到 405 服务器不支持所请求的方法
  234. 500 未知的服务器错误 503 已达到服务器容量 */
  235. if(StatusCode == HTTP_STATUS_MOVED ||StatusCode == HTTP_STATUS_REDIRECT || //是否需要重新定向
  236. StatusCode == HTTP_STATUS_REDIRECT_METHOD){
  237. CString strNewLocation;
  238. pHttpFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, strNewLocation); //返回HTTP请求中的回答或请求头
  239. int nPlace = strNewLocation.Find(_T("Location: "));
  240. if(nPlace == -1) //并未找到 说明站点地址改变
  241. THROW(new CInternetException(StatusCode)); //除去异常 错误
  242. strNewLocation = strNewLocation.Mid(nPlace + 10); //从'Location: '之后,删除'Location: ',存于变量
  243. nPlace = strNewLocation.Find('\n'); //寻找这一行的末尾
  244. if(nPlace > 0) strNewLocation = strNewLocation.Left(nPlace);//返回nPlace长度的字符串
  245. // close up the redirected site
  246. pHttpFile->Close(); //关闭CHttpFile 并释放其资源
  247. delete pHttpFile;
  248. pServer->Close(); //关闭CHttpConnection 并释放其资源
  249. delete pServer;
  250. // 检查原来的位置
  251. if(!AfxParseURL(strNewLocation, dwServiceType, //重定向的URL并未成功解析
  252. strServerName, strObject, nPort))
  253. THROW(new CInternetException(StatusCode)); //去除异常 错误
  254. if (dwServiceType != INTERNET_SERVICE_HTTP) //重定向的URL不是一个HTTP资源
  255. THROW(new CInternetException(StatusCode)); //除去异常 错误
  256. // 在新的位置尝试,并继续请求 获得HTTP请求相关联的状态号 同上
  257. pServer = MyConnect.GetHttpConnection(strServerName, nPort);
  258. pHttpFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET,
  259. strObject, NULL, 1, NULL, NULL);
  260. pHttpFile->AddRequestHeaders(_T("Accept: text/*\r\nUser-Agent: MFC\r\n"));
  261. pHttpFile->SendRequest();
  262. pHttpFile->QueryInfoStatusCode(StatusCode);
  263. }
  264. if (StatusCode != HTTP_STATUS_OK) //http状态错误
  265. THROW(new CInternetException(StatusCode)); //除去异常 错误
  266. }
  267. catch(CInternetException *pEx) //出错处理 并未关闭重定向站点
  268. {
  269. if(pServer!=NULL){
  270. pServer->Close();
  271. delete pServer;
  272. }
  273. if(pHttpFile!=NULL){
  274. pHttpFile->Close();
  275. delete pHttpFile;
  276. }
  277. pEx->Delete();
  278. MyConnect.Close();
  279. ptr->m_DownData.DeleThread(); //从共享数据区队列中删除该线程
  280. pDlg->Add(URL+"\r\n",0);
  281. return 0;
  282. }
  283. //message for "Connected"
  284. //if m_DownData is not full save the file
  285. bool isfull=!(ptr->m_DownData.IsFull());//若队列已满 isfull值为0,否则为非零值
  286. CString str_FileName; //内容提取后保存为本地文件
  287. ptr->m_DownData.GetFileName(str_FileName);//str_FileName为提取的内容在本地保存的文件名
  288. //内容提取后保存为本地文件
  289. CStdioFile LocalFile;
  290. //本地临时文件
  291. CStdioFile tempLocalFile;
  292. //提取变量
  293. CString dbTitle(""), dbUrl(""), dbText("");
  294. LocalFile.Open(str_FileName,CFile::modeCreate|
  295. CFile::modeWrite|CFile::typeText); //以扩展名.txt文件形式打开
  296. if(isfull) //若队列未满 打开一个windows的临时文件 .tmp为扩展名
  297. tempLocalFile.Open(str_FileName+".tmp",CFile::modeCreate|CFile::modeWrite|CFile::typeText);
  298. if(isfull) //向str_FileName.tmp文件写入数据
  299. tempLocalFile.WriteString(URL+_T("\n"));
  300. LocalFile.WriteString(URL+_T("\n")); //向str_FileName.txt文件写入数据
  301. dbUrl = URL;
  302. CString line;
  303. UINT w=0,k=0;
  304. int i=0,j=0;
  305. LPTSTR p;
  306. bool isUTF8 = false; //记录网页是否UTF-8编码
  307. //找出本页的标题
  308. while(pHttpFile->ReadString(line)) //逐行读取文件中的数据
  309. {//每次读取一行
  310. if (line.Find(_T("charset=utf-8")) != -1 || line.Find(_T("charset=UTF-8")) != -1)
  311. {
  312. isUTF8 = true;
  313. }
  314. if(isfull)tempLocalFile.WriteString(line+_T("\n"));//若队列未满 下一行
  315. i=line.Find(_T("<TITLE>"));
  316. if(i==-1) i=line.Find(_T("<Title>")); //i=-1,并未找到<TITLE>
  317. if(i==-1) i=line.Find(_T("<title>")); //i=-1,并未找到<Title>
  318. if(i!=-1) //找到<TITLE>、<Title>或<title>
  319. {
  320. i+=7;
  321. j=line.Find(_T("</")); //从<title>之后找'</'
  322. if(j!=-1)LocalFile.WriteString(line.Mid(i,j-i)+_T("\n"));//找到'</' 将<title>和</title>之间的标题写入下一行
  323. //if(j!=-1)
  324. //{
  325. // dbTitle = line.Mid(i,j-i);
  326. //}
  327. else{
  328. LocalFile.WriteString(line.Mid(i));//从第i个字符开始,将该行的标题写入文件
  329. //dbTitle.Append(line.Mid(i));
  330. while(pHttpFile->ReadString(line))
  331. {
  332. if(isfull) //队列未满
  333. tempLocalFile.WriteString(line+_T("\n"));// 从下一行开始
  334. j=line.Find(_T("</")); //再次寻找'</'
  335. if(j==-1){
  336. LocalFile.WriteString(line);//并未找到 标题在该行未结束 继续下一行 continue
  337. //dbTitle.Append(line);
  338. continue;
  339. }
  340. LocalFile.WriteString(line.Left(j)+"\n");//将'</' 左侧的字符写入文件 得到完整的标题
  341. //dbTitle.Append(line.Left(j));
  342. break;
  343. }
  344. }
  345. break; //找到完整的标题 直接退出循环
  346. }
  347. if(line.Find(_T("</HAED>"))!=-1 || line.Find(_T("</Head>"))!=-1 || line.Find(_T("</head>"))!=-1){
  348. LocalFile.WriteString(_T("Untitled Page\n"));//未找到<TITLE>、<Title>或<title>
  349. //但找到"</HAED>" "</Head>"或"</head>"
  350. //dbTitle = _T("Untitled Page");
  351. break; //说明该网页无标题
  352. }
  353. };
  354. bool body=false;
  355. while(pHttpFile->ReadString(line))
  356. {
  357. if(isfull)tempLocalFile.WriteString(line+_T("\n")); //走向下一行
  358. if(line.Find(_T("<BODY"))!=-1 || line.Find(_T("<body"))!=-1 || line.Find(_T("<Body"))!=-1)
  359. body=true; //找到 "<BODY" "<body" 或 "<Body" 变量body值赋值为true
  360. if(body && line.Find('>')!=-1) break;
  361. }
  362. //对主体内容的过滤
  363. while(pHttpFile->ReadString(line))
  364. {
  365. if(isfull)tempLocalFile.WriteString(line+_T("\n"));//队列未满 从下一行开始
  366. p=line.GetBuffer(1024); //重新获取其内部字符缓冲区的指针p
  367. ptr->TrimString((LPTSTR)p,w,k,TRUE); //-设置主要保留中文
  368. line.ReleaseBuffer(); //将申请的1024个空间多余的释放掉 可与GetBuffer配合使用
  369. if(line!="") //如果tempLocalFile文件该行不为空
  370. {
  371. int f=0,g=0;
  372. while((g=line.Find(_T("&nbsp;"),f))!=-1) //寻找&nbsp 即空格
  373. {//去除&nbsp;符号
  374. line.Delete(g,6);
  375. line.Insert(g,_T(" ")); //将&nbsp替换为空格
  376. f=g;
  377. }
  378. while((g=line.Find(_T("&gt;"),f))!=-1) //寻找&gt; 即'>'
  379. {//去除&gt;符号
  380. line.Delete(g,4);
  381. line.Insert(g,_T(">")); //将&gt;替换为'>'
  382. f=g;
  383. }
  384. while((g=line.Find(_T("&lt;"),f))!=-1)
  385. {//去除&lt;符号
  386. line.Delete(g,4);
  387. line.Insert(g,_T("<"));
  388. f=g;
  389. }
  390. line.TrimLeft(); //该行左边的空格除去
  391. line.TrimRight(); //该行右边的空格除去
  392. if(line!="") //该行为空
  393. LocalFile.WriteString(line+_T(" "));//LocalFile文件相应为空
  394. //dbText.Append(line+_T(" "));
  395. }
  396. }
  397. LocalFile.Close(); //关闭LocalFile文件
  398. LocalFile.Open(str_FileName, CFile::modeRead|CFile::typeText);
  399. LocalFile.ReadString(dbUrl);
  400. LocalFile.ReadString(dbTitle);
  401. CString tempLine;
  402. while (LocalFile.ReadString(tempLine))
  403. {
  404. dbText.Append(tempLine);
  405. dbText.Append(_T(" "));
  406. }
  407. LocalFile.Close();
  408. if (isUTF8)
  409. {
  410. ptr->UTF8ToGB2312(dbTitle.GetBuffer(), dbTitle.GetLength(), dbTitle);
  411. ptr->UTF8ToGB2312(dbText.GetBuffer(), dbText.GetLength(), dbText);
  412. }
  413. int endPos = dbTitle.Find(_T("</"));
  414. if (endPos > 0)
  415. {
  416. dbTitle = dbTitle.Mid(0, endPos);
  417. }
  418. ptr->InsertDB(dbUrl, dbTitle, dbText);
  419. if(isfull) tempLocalFile.Close();
  420. //查找临时文件中的链接
  421. if(isfull){
  422. FindURL(str_FileName+_T(".tmp"),ptr);//查找临时文件中的链接
  423. // DeleteFile(str_FileName+_T(".tmp"));//删除临时文件
  424. }
  425. pHttpFile->Close(); //关闭CHttpFile 并释放其资源
  426. delete pHttpFile;
  427. pServer->Close(); //关闭CHttpConnection 并释放其资源
  428. delete pServer;
  429. MyConnect.Close();
  430. //状态显示
  431. pDlg->Add(URL+_T("\r\n"),1);
  432. ptr->m_DownData.DeleThread(); //线程结束 从数据区删除一个线程记录
  433. return 1;
  434. }
  435. /*==========================================================================================================*/
  436. /
  437. // MainThread message handlers
  438. void MainThread::Run(CString &str_Begin){
  439. m_DownData.AddURL(str_Begin);//-向共享数据区URL队列加入根URL
  440. if(m_DownData.AddThread())
  441. AfxBeginThread(DownloadFile,this);//-访问根URL
  442. while(!m_bDone && !(m_DownData.IsEmpty() && m_DownData.GetCurThread()==0)){
  443. //依次启动工作者线程,根据共享数据区URL队列依次到指定URL下载
  444. Sleep(100);
  445. if(ThreadPause) continue;//判断全局变量ThreadPause,是否暂停线程
  446. if(m_DownData.AddThread()) AfxBeginThread(DownloadFile,this);
  447. }
  448. Sleep(1000);
  449. AfxMessageBox(_T("任务完成!"));
  450. ExitInstance();
  451. }
  452. /*=========================================================================================================
  453. 函数功能:过滤掉字符串中的html语言标签
  454. 入口参数:
  455. LPTSTR pszBuffer 字符串指针指向被处理的字符串,以'\0'结尾
  456. UINT &w 已经出现的"<"数目
  457. UINT &K 已经出现的"{"数目
  458. bool chinese 是否主要保留中文
  459. 函数的抽象算法:
  460. 对于html代码,出现在{}中间的被视为函数体会被无条件的删除,出现在<>中间的代码会当作语言标签被删除。
  461. 如果是主要保留中文,为了更好的过滤,若一行中没有一个中文字符,则省略该行。
  462. =========================================================================================================*/
  463. bool MainThread::TrimString(LPTSTR pszBuffer,UINT &w,UINT &k,bool chinese){
  464. LPTSTR pszSource = pszBuffer;
  465. LPTSTR pszDest = pszBuffer;
  466. LPTSTR pszTemp = pszBuffer;
  467. bool ch=FALSE;
  468. bool mark=FALSE;
  469. while (*pszSource != '\0'){
  470. if(!ch && (*pszSource)<0) ch=TRUE;//本段字符中是否含有中文字符(汉字机内码以1开始,工作日志(四)有资料)
  471. if(*pszSource == '{')k++;
  472. if(k==0){//如果未被包含在{}中
  473. if(w!=0){//如果包含在<>中
  474. if(*pszSource == '>') w--;
  475. else if(*pszSource == '<') w++;
  476. }
  477. else{//未包含在<>中
  478. if (*pszSource == '<'){
  479. w++;
  480. mark=TRUE;
  481. }
  482. else{
  483. if(mark){//说明是'>'后第一个字符;每段文字以空格分开
  484. *pszDest=' ';
  485. pszDest++;
  486. mark=FALSE;
  487. }
  488. *pszDest = *pszSource;
  489. pszDest++;
  490. }
  491. }
  492. }
  493. if(*pszSource == '}') k--;
  494. pszSource++;
  495. }
  496. //结束处理
  497. if(chinese){
  498. if(ch) *pszDest = '\0';
  499. else *pszTemp= '\0';//若一行中没有一个中文字符,则省略该行
  500. }
  501. else *pszDest = '\0';
  502. return true;
  503. }
  504. void MainThread::InsertDB(CString dbUrl, CString dbTitle, CString dbText)
  505. {
  506. CoInitialize(NULL);
  507. _ConnectionPtr pConn(__uuidof(Connection));
  508. _RecordsetPtr pRst(__uuidof(Recordset));
  509. _CommandPtr pCmd(__uuidof(Command));
  510. _variant_t RecordsAffected; //申请一个_variant_t类型的的变量
  511. pConn->ConnectionString="Provider=MIcrosoft.Jet.OLEDB.4.0;Data source=web.mdb";
  512. pConn->Open("","","",adConnectUnspecified);
  513. dbText.Replace(_T("'"), _T("''")); //单引号转义
  514. CString sql = "INSERT INTO crawler(Url,Title,Content) VALUES ('" + dbUrl + "','" + dbTitle + "','" + dbText + "')";
  515. //MessageBox(NULL, sql, NULL, NULL);
  516. try
  517. {
  518. pRst=pConn->Execute(sql.GetBuffer(sql.GetLength()), &RecordsAffected,adCmdText);
  519. }
  520. catch (...)
  521. {
  522. ;
  523. }
  524. //pRst->Close(); //若有此句可以实现插入,但会产生runtime错误提示
  525. pConn->Close();
  526. pCmd.Release();
  527. pRst.Release();
  528. pConn.Release();
  529. CoUninitialize();
  530. }
  531. void MainThread::UTF8ToGB2312(char *pText, int nLen, CString &strOutput)
  532. {
  533. if (nLen <= 0)
  534. {
  535. return ;
  536. }
  537. char *PBuf = strOutput.GetBuffer(nLen);
  538. char cTemp[4] = {0};
  539. int i = 0, j = 0;
  540. // Jump "EF BB BF " if necessary.
  541. if (memcmp(pText, "\xef\xbb\xbf ", 3) == 0)
  542. {
  543. i = 3;
  544. }
  545. while(i < nLen)
  546. {
  547. if(pText[i] > 0)
  548. {
  549. PBuf[j++] = pText[i++];
  550. }
  551. else
  552. {
  553. WCHAR Wtemp;
  554. char* uchar = (char *)&Wtemp;
  555. uchar[1] = ((pText[i] & 0x0F) << 4) + ((pText[i+1] >> 2) & 0x0F);
  556. uchar[0] = ((pText[i+1] & 0x03) << 6) + (pText[i+2] & 0x3F);
  557. WideCharToMultiByte(CP_ACP, NULL, &Wtemp, 1, cTemp, sizeof(WCHAR), NULL, NULL);
  558. PBuf[j] = cTemp[0];
  559. PBuf[j+1] = cTemp[1];
  560. i += 3;
  561. j += 2;
  562. }
  563. }
  564. PBuf[j] = '\0';
  565. strOutput.ReleaseBuffer();
  566. }


创作不易,小小的支持一下吧!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/818145
推荐阅读
相关标签
  

闽ICP备14008679号