#include<windows.h>
#include<Wininet.h>
#include<iostream>
#include<fstream>
#include<string>
#include<locale.h>
#pragma comment(lib,"WinInet.lib")
using namespace std;
string Utf8ToGbk(const char *src_str)//utf-8转GBK
{
//该函数可以映射一个unicode字符串到一个多字节字符串,执行转换的代码页、接收转换字符串、允许额外的控制等操作。
// int MultiByteToWideChar(字符串转换宽字符
//UINT CodePage,指定转换的字符集 CP_ACP:ANSI字符集;CP_MACCP:Macintosh代码页;CP_OEMCP: OEM代码页;CP_SYMBOL: 符号字符集(42);CP_THREAD_ACP: 当前线程ANSI代码页;CP_UTF7: 使用UTF-7转换;CP_UTF8: 使用UTF-8转换。
//DWORD dwFlags,转换形式,默认填0;
//LPCSTR lpMultiByteStr,指向将被转换字符串的字符
//int cchMultiByte,指定由参数lpMultiByteStr指向的字符串中字节的个数,参数为-1,字符串以空字符\0结束
//LPWSTR lpWideCharStr,指向接收被转换字符串的缓冲区
//int cchWideChar 指定由参数lpWideCharStr指向的缓冲区的宽字符个数。若此值为零,函数返回缓冲区所必需的宽字符数
//);返回值为宽字符数
int len = MultiByteToWideChar(CP_UTF8, 0, src_str, -1, NULL, 0);//获取转换的宽字符长度
wchar_t* wszGBK = new wchar_t[len + 1];
memset(wszGBK, 0, len * 2 + 2);//初始化wszGBK内存
MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wszGBK, len);//转换src_str为宽字符到wszGBK
len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);//获取宽字符wszGBK转换为asic字符的长度
char* szGBK = new char[len + 1];
memset(szGBK, 0, len + 1);//初始化szGBK内存
WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);//转换wszGBK为szGBK
string strTemp(szGBK);
if (wszGBK) delete[] wszGBK;
if (szGBK) delete[] szGBK;
return strTemp;
}
int main()
{
//setlocale(LC_ALL, "zh_CN");
HINTERNET hINet, hHttpFile;
char szSizeBuffer[1024];
DWORD dwLengthSizeBuffer = sizeof(szSizeBuffer);
//为了使网络连接生效,必须用函数InternetOpen函数创建一个HINTERNET根句柄
hINet = InternetOpenW(L"Microsoft Internet Explorer", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 ); //InternetOpen初始化WININET.DLL
// INTERNET_OPEN_TYPE_PRECONFIG应用程序到注册表中搜索代理设置。一般而言,这个选项是最好的选择,因为绝大多数的应用包括web浏览器都使用它。
if ( !hINet )
{
cout << "InternetOpen fail" << endl;
// return 1;
}
//通过一个完整的FTP,Gopher或HTTP网址打开一个资源。
// HINTERNET InternetOpenUrl (__in HINTERNET hInternet//HINTERNET句柄
// ,__in LPCTSTR lpszUrl//url连接地址
// ,__in LPCTSTR lpszHeader//一个空字符结束的字符串变量的指针,指定发送到HTTP服务器 的头信息。
// ,__in DWORD值dwHeadersLength/头信息长度/
// ,__in的DWORD dwFlags
// ,__in DWORD_PTR dwContext 一个 指向一个应用程序定义的值,将随着返回的句柄,一起传递给回调函数。
//) ;
hHttpFile = InternetOpenUrlW(hINet, L"https://news.sina.com.cn/c/xl/2020-11-15/doc-iiznctke1462173.shtml", NULL, 0, 0, 0); //这个函数连接到一个网络服务器上并且最被从服务器上读取数据
if(!hHttpFile)
{
cout << "error open url" << endl;
// return 1;
}
// 用来查询一个HTTP请求的信息。
// BOOL WINAPI HttpQueryInfo(
//HINTERNET hRequest,//HTTP请求返回的句柄。
//DWORD dwInfoLevel,//指定的属性的组合查询和请求进行修改的标志, HTTP_QUERY_CONTENT_LENGTH,//接收到的资源大小
//LPVOID lpBuffer,指针指向的缓冲区,接收的信息。
//LPDWORD lpdwBufferLength,指针的值包含的数据缓冲区的长度。
//LPDWORD lpdwIndex
//);
BOOL bQuery = HttpQueryInfo(hHttpFile,
HTTP_QUERY_CONTENT_LENGTH,//接收到的资源大小
szSizeBuffer,//指针指向的缓冲区,接收的信息。
&dwLengthSizeBuffer, NULL); //得到关于文件的信息
if(bQuery ==false)
{
InternetCloseHandle(hINet);
cout << "error query info" << endl;
// return 3;
}
int FileSize=atol(szSizeBuffer); //atol函数把字符串转换成长整型数
string revData;
revData.resize(1024);
DWORD dwBytesRead;
int i=0;
// ofstream out_file("duhui.txt");
FILE *pfile;
pfile=fopen("html.txt","w");
while (1)
{
/*BOOL bRead = InternetReadFile(hHttpFile, &revData[0], FileSize, &dwBytesRead); */ //web浏览器将在InternetReadFile上循环 ,不停地从Internet上读入数据块。
BOOL bRead = InternetReadFile(hHttpFile, &revData[0], 1024, &dwBytesRead);
char stemp[1024];
strcpy(stemp,Utf8ToGbk(&revData[0]).data());
cout<<stemp<<endl;
fputs(stemp,pfile);
if(strstr(&stemp[0],"</html>")!=NULL)
break;
//cout<<revData;
//Sleep(700);
}
fclose(pfile);
InternetCloseHandle(hHttpFile); //关闭句柄
InternetCloseHandle(hINet);
cout << "抓取成功!/n" << endl;
system("pause");
return 0;
}