本人是初學MFC,這幾天都要弄怎么抓取網頁代碼,一開始是一頭霧水,不過最后多虧網上的豐富資源,讓我有所收獲,我也幫助新手們,下面是我自己參考網上資料所得的。
1 #pragma once 2 3 4 //抓取網頁代碼封裝類 5 6 #include <afxinet.h> //所需要的函數的頭文件。 7 8 9 class CGetInternet 10 { 11 public: 12 CGetInternet(); 13 virtual ~CGetInternet(); 14 15 //添加變量 16 protected: 17 CString m_strError; //接受錯誤信息 18 CString m_HttpCode; //接受抓取的網頁代碼 19 UINT PageCode; //CP_UTF8:65001 CP_ACP:0 轉換代碼用 20 21 //添加自定義函數 22 public: 23 BOOL OnInitSession(CInternetSession &session);//判斷鏈接是否成功。可以不要 24 25 CString GetHttpCode(CString &url); //主要接口,輸入網址,獲取代碼 26 27 int OnProcessError(int dwRetcode, CInternetSession &session, 28 CHttpConnection *pServer, CHttpFile *pFile);//鏈接錯誤函數 29 30 31 };
1 #include "stdafx.h" 2 #include "GetInternet.h" 3 4 //驗證的字符串 5 const TCHAR szHeaders[] = _T("Accept: _T/*\r\nUser-Agent: LCD's Infobay Http Client\r\n"); 6 7 //構造函數 8 CGetInternet::CGetInternet() 9 { 10 PageCode = 65001; //因為我們的網址是UTF8格式,所以用65001; 11 m_HttpCode = _T(""); 12 } 13 14 //析構函數 15 CGetInternet::~CGetInternet() 16 { 17 m_strError.ReleaseBuffer(); 18 } 19 20 //主要接口,輸入網址,獲取代碼 21 CString CGetInternet::GetHttpCode(CString &url) 22 { 23 //獲取網頁的初始化工作 24 CInternetSession session(NULL, 0); 25 CHttpFile *htmlFile = NULL; 26 TCHAR sRecv[1024]; //接受緩存代碼。 27 28 //錯誤判斷初始化 29 DWORD dwServiceType = 0; 30 DWORD dwHttpRequestFlags = INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_AUTO_REDIRECT; 31 CString strServerName = _T(""); 32 CString strObject = _T(""); 33 INTERNET_PORT nPort = 0; 34 CString StrContent = _T(""); 35 DWORD dwRetcode = -1; 36 37 CHttpConnection *pServer = NULL; 38 39 try 40 { 41 if (!OnInitSession(session)) //判斷鏈接是否成功;可以不要 42 { 43 return NULL; 44 } 45 if (!AfxParseURL(url, dwServiceType, strServerName, strObject, nPort) || dwServiceType != INTERNET_SERVICE_HTTP) 46 { 47 m_strError = _T("非法的URL"); 48 return NULL; 49 } 50 51 pServer = session.GetHttpConnection(strServerName, nPort); 52 53 54 if (pServer == NULL) 55 { 56 m_strError = _T("無法與服務器建立連接"); 57 return NULL; 58 } 59 //下面第一個可以為1 打開http鏈接 60 htmlFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET, strObject, 61 NULL, 1, NULL, NULL, dwHttpRequestFlags); 62 63 if (htmlFile == NULL) 64 { 65 m_strError = _T("無法與服務器建立連接"); 66 return NULL; 67 } 68 69 ///////////////////////////////////////////////// 70 try 71 { //調用此成員函數添加一個或多個HTTP請求標頭到HTTP請求處理。AddRequestHeaders 72 // 73 if (!htmlFile->AddRequestHeaders(szHeaders) || !htmlFile->SendRequest()) 74 { 75 m_strError = _T("網絡錯誤-無法發送請求報頭"); 76 return NULL; 77 } 78 } 79 catch (CInternetException *ex) 80 { 81 StrContent.Empty(); 82 m_strError = _T("無法發送http報頭,可能網絡狀況有問題"); 83 ex->Delete(); 84 return NULL; 85 } 86 ////////////////////////////////////////////////////////////////////////// 87 88 if (!htmlFile->QueryInfoStatusCode(dwRetcode)) 89 { 90 m_strError = _T("網絡錯誤-無法查詢反饋代碼"); 91 return NULL; 92 } 93 94 if (dwRetcode >= 200 && dwRetcode < 300) 95 { 96 try 97 { 98 //htmlFile = (CHttpFile*)session.OpenURL(url);//打開鏈接 99 100 while (htmlFile->ReadString(sRecv, 1024)) 101 { 102 // 編碼轉換,可解決中文亂碼問題 103 //gb2312轉為unicode,則用CP_ACP 104 //gbk轉為unicode,也用CP_ACP 105 //utf-8轉為unicode,則用CP_UTF8 106 int nBufferSize = MultiByteToWideChar(PageCode, 0, (LPCSTR)sRecv, -1, NULL, 0); 107 108 wchar_t *pBuffer = new wchar_t[nBufferSize + 1]; 109 memset(pBuffer, 0, (nBufferSize + 1) *sizeof(wchar_t)); 110 111 //gb2312轉為unicode,則用CP_ACP 112 //gbk轉為unicode,也用CP_ACP 113 //utf-8轉為unicode,則用CP_UTF8 114 MultiByteToWideChar(PageCode, 0, (LPCSTR)sRecv, -1, pBuffer, nBufferSize *sizeof(wchar_t)); 115 116 m_HttpCode += pBuffer; 117 m_HttpCode += "\r\n"; 118 delete pBuffer; 119 } 120 121 htmlFile->Close(); 122 session.Close(); 123 delete htmlFile; 124 125 //多余。 126 CFile file; 127 file.Open(_T("test2.txt"), CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite); 128 file.Write(m_HttpCode, m_HttpCode.GetLength()); 129 file.Close(); 130 131 return m_HttpCode; 132 133 } 134 catch (CInternetException* pEx) 135 { 136 m_strError = _T("接收數據錯誤"); 137 pEx->Delete(); 138 139 //因為是CString,所以返回NULL,而不是0; 140 return NULL; 141 } 142 return StrContent; 143 144 } 145 else 146 { 147 //讀取失敗,將buffer清空。 148 StrContent.Empty(); 149 150 //發送錯誤。 151 OnProcessError(dwRetcode, session, pServer, htmlFile); 152 153 return NULL; 154 } 155 156 } 157 catch (CInternetException* pEx) 158 { 159 m_strError = _T("網絡錯誤"); 160 161 pEx->Delete(); 162 return NULL; 163 } 164 165 return NULL; 166 } 167 168 169 //判斷鏈接是否成功。可以不要 170 BOOL CGetInternet::OnInitSession(CInternetSession &session) 171 { 172 //超時設置很重要!如果設置太小回引起服務器超時,如果設置太大則回引起線程掛起。 173 //在重試連接之間的等待的延時值在毫秒級。 174 //網絡連接請求時間超時值在數毫秒級。如果連接請求時間超過這個超時值,請求將被取消。缺省的超時值是無限的。 175 //在網絡連接請求時的重試次數。如果一個連接企圖在指定的重試次數后仍失敗,則請求被取消。缺省值為5。 176 try 177 { 178 if (!session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 10000) || //超時 179 !session.SetOption(INTERNET_OPTION_CONNECT_BACKOFF, 1000) || //延遲 180 !session.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 3) || //重試 181 !session.SetOption(INTERNET_OPTION_RECEIVE_TIMEOUT, 60000) || //最大超時 182 !session.EnableStatusCallback(TRUE)) //建立一個狀態回調例程。異步操作需要 183 { 184 return FALSE; 185 } 186 else 187 { 188 return TRUE; 189 } 190 } 191 catch (CInternetException* pEx) 192 { 193 pEx->GetErrorMessage(m_strError.GetBuffer(0), 1023); 194 pEx->Delete(); 195 196 return FALSE; 197 } 198 199 } 200 201 //鏈接錯誤函數 202 int CGetInternet::OnProcessError(int dwRetcode, CInternetSession &session, 203 CHttpConnection *pServer, CHttpFile *pFile) 204 { 205 switch (dwRetcode) 206 { 207 case 100: 208 m_strError = _T("客戶方錯誤-繼續 [Continue]"); 209 break; 210 // 211 case 101: 212 m_strError = _T("客戶方錯誤-交換協議 [witching Protocols]"); 213 break; 214 // 215 case 204: 216 m_strError = _T("網頁內容為空 [No Content]"); 217 break; 218 //------------------------------------------------------------ 219 case 400: 220 m_strError = _T("錯誤請求 [Bad Request]"); 221 break; 222 // 223 case 401: 224 m_strError = _T("網頁需要驗證信息 [Unauthorized]"); 225 break; 226 // 227 case 402: 228 m_strError = _T("網頁需要付費 [Payment Required]"); 229 break; 230 // 231 case 403: 232 m_strError = _T("禁止訪問 [Forbidden]"); 233 break; 234 // 235 case 404:// 236 m_strError = _T("沒有找到網頁 [Not Found]"); 237 break; 238 // 239 case 405: 240 m_strError = _T("不允許Http訪問該文件 [Method Not Allowed]"); 241 break; 242 // 243 case 406: 244 m_strError = _T("該文件不允許訪問 [Not Acceptable]"); 245 break; 246 // 247 case 407: 248 m_strError = _T("該文件需要代理認證 [Proxy Authentication Required]"); 249 break; 250 // 251 case 408: 252 m_strError = _T("對該文件請求超時 [Request Time-out]"); 253 break; 254 // 255 case 409: 256 m_strError = _T("對該文件訪問沖突 [Conflict]"); 257 break; 258 // 259 case 410: 260 m_strError = _T("對該文件訪問失敗 [Gone]"); 261 break; 262 // 263 case 411: 264 m_strError = _T("該文件需要長度信息 [Length Required]"); 265 break; 266 // 267 case 412: 268 m_strError = _T("請求條件失敗 [Precondition Failed]"); 269 break; 270 // 271 case 413: 272 m_strError = _T("請求文件實體太大 [Request Entity Too Large]"); 273 break; 274 // 275 case 414: 276 m_strError = _T("請求的URI太長 [Request-URI Too Large]"); 277 break; 278 // 279 case 415: 280 m_strError = _T("不支持媒體類型 [Unsupported Media Type]"); 281 break; 282 // 283 case 416: 284 m_strError = _T("隊列請求失敗 [Requested range not satisfiable]"); 285 break; 286 // 287 case 417: 288 m_strError = _T("預期失敗 [Expectation Failed]"); 289 break; 290 //-------------------------------------------------------------- 291 case 500: 292 m_strError = _T("服務器內部錯誤 [Internal Server Error]"); 293 break; 294 // 295 case 501: 296 m_strError = _T("未實現請求 [Not Implemented]"); 297 break; 298 // 299 case 502: 300 m_strError = _T("網關失敗 [Bad Gateway]"); 301 break; 302 // 303 case 503: 304 m_strError = _T("沒有找到服務器 [Service Unavailable]"); 305 break; 306 // 307 case 504: 308 m_strError = _T("網關超時 [Gateway Time-out]"); 309 break; 310 // 311 case 505: 312 m_strError = _T("服務器不支持系統使用的HTTP版本 [HTTP Version not supported]"); 313 break; 314 // 315 } 316 317 try 318 { 319 if (pFile != NULL) SafeDelete(pFile); 320 if (pServer != NULL) SafeDelete(pServer); 321 322 session.Close(); 323 324 return 0; 325 } 326 catch (CInternetException *pEx) 327 { 328 pEx->GetErrorMessage(m_strError.GetBuffer(0), 1024); 329 pEx->Delete(); 330 331 return 0; 332 } 333 }
//多余。
CFile file;
file.Open(_T("test2.txt"), CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite);
file.Write(m_HttpCode, m_HttpCode.GetLength());
file.Close();
這個是用來查看抓取的代碼。
PS:
需要在stdafx.h加入這個
//刪除指針
#define SafeDelete(pData) { try { delete pData; } catch (...) { ASSERT(FALSE); } pData=NULL; }
1,創建一個MFC的基本對話框,
2.創建一個c++類,將上面代碼加入,
3.在OnInitDialog函數中調用:
// TODO: 在此添加額外的初始化代碼
CGetInternet get1;
CString url = _T("http://www.tqyb.com.cn/index.html");
get1.GetHttpCode(url);
以上。
感謝:
http://code.it168.com/v/yigecongwangyetaglimianfenxiurlheurlbiaotideleivcyuandaima/GetWeb.cpp
http://blog.chinaunix.net/uid-27213819-id-3781188.html
http://www.gymsaga.com/project/728.html
感謝這三位博主的開源。
