地址: http://blog.csdn.net/hujkay
作者:Jekkay Hu(34538980@qq.com)
关键词:Windows,curl,ssl,  visual c++ 2005, libcurl, https,网页抓取
时间: 2014/2/18

1. 概述

由于Curl提供强大的网络功能,支持HTTP,HTTPS, DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet ,TFTP等,已成为应用最为广泛的轻量级网络库之一。libCurl支持Windows,但如果在Win 平台使用VC开发的话,则需要下载msvc的版本,其下载地址是:http://curl.haxx.se/download/,如:libcurl-7.19.3-win32-ssl-msvc.zip。

目前Curl的的最新版本已经是7.35.0,但是官网提供的msvc的版本仍然是2009年2月发布的7.19.3版本,而且还没有含静态openssl的lib,这就意味写个小exe程序的话,还得打包好几个Openssl DLL进去,挺麻烦的,所以我就重新编译了一个含Openssl静态库,这个库算是我编译的最大的库了,达到25M,下载地址:

  1. 已编译好含SSL的静态libcurl 7.35.0[VC2005].zip
  2. http://download.csdn.net/detail/hujkay/6931345

2. 使用

我以MFC Dialog based工程为例,介绍如何在Windons+VC2005上使用libcurl 7.35.0静态库。

2.1. 创建工程

打开Visual studio 2005,直接创建一个MFC工程,工程类型选择基于对话框[Dialog based]的就行,编码方式取消Unicode,这样就可以使用ANSI编码.

2.2  配置工程属性

右键工程属性,设置Curl的头文件目录路径,如下图:

配置库的链接方式和编码方式,如下图:

配置Runtime library,Debug模式为/MTD,Rlease模式为/MT

然后在Preprocesser里面添加预订义宏CURL_STATICLIB,如下图:

Debug模式和Release模式,配置的内容是一样的。

然后在stdafx.h文件最后面,添加如下代码:

  1. //// 添加CURL库
  2. #include <curl/curl.h>
  3. //// 带SSL的静态链接库
  4. #ifdef _DEBUG
  5. #pragma message("======编译======[DEBUG] CURL库=====")
  6. #pragma comment(lib,"libcurld.lib")
  7. #else
  8. #pragma message("======编译======[Release] CURL库=====")
  9. #pragma comment(lib,"libcurl.lib")
  10. #endif
  11. #pragma comment(lib,"wldap32.lib")
  12. #pragma comment(lib,"ws2_32.lib")

2.3  封装Curl库访问

为了使得Curl访问更加方便,我简单封装了一下Curl的访问类,代码如下:

VVCurl.h的源码如下:

  1. #pragma once
  2. #include <string>
  3. enum CURL_TYPE {CURL_GET=1,CURL_POST=2};
  4. class CVVCurl
  5. {
  6. public:
  7. CVVCurl(void);
  8. ~CVVCurl(void);
  9. BOOL            Init(CString strProxyAddr=_T(""),INT nPort=80) ;
  10. // 释放资源
  11. void            Release();
  12. // 打开指定的网页
  13. BOOL            OpenURL(std::string strURL,CURL_TYPE ntype = CURL_GET);
  14. BOOL            OpenURL(std::string strURL,std::string strPostData,CURL_TYPE ntype = CURL_POST);
  15. // 获取网页内容
  16. const char *    GetHeadContent() { return m_headcontent.c_str() ;} ;
  17. size_t          GetHeadContentLength() { return m_headcontent.size() ;} ;
  18. const char *    GetBodyContent() { return m_bodycontent.c_str() ;} ;
  19. size_t          GetBodyContentLength() { return m_bodycontent.size() ;} ;
  20. protected:
  21. BOOL            InitCurlHandle() ;
  22. BOOL            ReleaseCurlHandle() ;
  23. BOOL            DeleteCookieFile() ;
  24. BOOL            SetCurlHandleOpt() ;
  25. protected:
  26. // 句柄
  27. CURL *              m_pcurl;
  28. // 获取的内容
  29. std::string         m_headcontent ;
  30. std::string         m_bodycontent ;
  31. std::string         m_debugcontent ;
  32. // agent
  33. std::string         m_agent ;
  34. // cookie
  35. std::string         m_cookiepath ;
  36. // proxy
  37. std::string         m_strProxyServer ;
  38. // port
  39. int                 m_nPort ;
  40. };

VVCurl.cpp的源码如下:

  1. #include "StdAfx.h"
  2. #include "VVCurl.h"
  3. //#include "../include/Util.h"
  4. /*
  5. ptr是指向存储数据的指针,
  6. size是每个块的大小,
  7. nmemb是指块的数目,
  8. stream是用户参数。
  9. 所以根据以上这些参数的信息可以知道,ptr中的数据的总长度是size*nmemb
  10. */
  11. static size_t call_wirte_func(const char *ptr, size_t size, size_t nmemb, std::string *stream)
  12. {
  13. size_t len  = size * nmemb;
  14. stream->append(ptr, len);
  15. return len;
  16. }
  17. // 返回http header回调函数
  18. static size_t header_callback(const char  *ptr, size_t size, size_t nmemb, std::string *stream)
  19. {
  20. size_t len  = size * nmemb;
  21. stream->append(ptr, len);
  22. return len;
  23. }
  24. static int debug_callback (CURL * pcurl, curl_infotype ntype, char * ptr, size_t size, std::string  * stream)
  25. {
  26. int len  = (int)size;
  27. stream->append(ptr, len);
  28. return len;
  29. }
  30. CVVCurl::CVVCurl(void)
  31. {
  32. m_pcurl = NULL ;
  33. m_agent = _T("Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36 LBBROWSER") ;
  34. m_cookiepath = _T("cookie.txt") ; //CUtil::GetRandTempPath(_T("_cookie.txt"));
  35. }
  36. CVVCurl::~CVVCurl(void)
  37. {
  38. Release() ;
  39. }
  40. BOOL CVVCurl::Init(CString strProxyAddr,INT nPort)
  41. {
  42. m_nPort = nPort ;
  43. m_strProxyServer = strProxyAddr ;
  44. return InitCurlHandle() ;
  45. }
  46. void CVVCurl::Release()
  47. {
  48. ReleaseCurlHandle() ;
  49. DeleteCookieFile() ;
  50. }
  51. BOOL CVVCurl::InitCurlHandle()
  52. {
  53. if( NULL == m_pcurl)
  54. {
  55. m_pcurl = curl_easy_init() ;
  56. }
  57. if( NULL == m_pcurl ){
  58. ASSERT(FALSE) ;
  59. return FALSE ;
  60. }
  61. SetCurlHandleOpt() ;
  62. return TRUE ;
  63. }
  64. BOOL CVVCurl::SetCurlHandleOpt()
  65. {
  66. if( NULL == m_pcurl )
  67. return FALSE ;
  68. // 设置Agent
  69. curl_easy_setopt(m_pcurl, CURLOPT_USERAGENT, m_agent.c_str());
  70. // 官方下载的DLL并不支持GZIP,Accept-Encoding:deflate, gzip
  71. curl_easy_setopt(m_pcurl, CURLOPT_ENCODING, "");
  72. //跳过服务器SSL验证,不使用CA证书
  73. curl_easy_setopt(m_pcurl, CURLOPT_SSL_VERIFYPEER, 0L);
  74. //如果不跳过SSL验证,则可指定一个CA证书目录
  75. //curl_easy_setopt(curl, CURLOPT_CAPATH, "this is ca ceat");
  76. //验证服务器端发送的证书,默认是 2(高),1(中),0(禁用)
  77. curl_easy_setopt(m_pcurl, CURLOPT_SSL_VERIFYHOST, 0L);
  78. /* 与服务器通信交互cookie,默认在内存中,可以是不存在磁盘中的文件或留空 */
  79. curl_easy_setopt(m_pcurl, CURLOPT_COOKIEFILE, m_cookiepath.c_str());
  80. /* 与多个CURL或浏览器交互cookie,会在释放内存后写入磁盘文件 */
  81. curl_easy_setopt(m_pcurl, CURLOPT_COOKIEJAR, m_cookiepath.c_str()) ;
  82. //设置重定向的最大次数
  83. curl_easy_setopt(m_pcurl, CURLOPT_MAXREDIRS, 5);
  84. // 设置自动设置refer字段
  85. curl_easy_setopt ( m_pcurl, CURLOPT_AUTOREFERER, 1 );
  86. //设置301、302跳转跟随location
  87. curl_easy_setopt(m_pcurl, CURLOPT_FOLLOWLOCATION, 1);
  88. //抓取内容后,回调函数
  89. curl_easy_setopt(m_pcurl, CURLOPT_WRITEFUNCTION, call_wirte_func);
  90. curl_easy_setopt(m_pcurl, CURLOPT_WRITEDATA, &m_bodycontent );
  91. //抓取头信息,回调函数
  92. curl_easy_setopt(m_pcurl, CURLOPT_HEADERFUNCTION, header_callback );
  93. curl_easy_setopt(m_pcurl, CURLOPT_HEADERDATA, &m_headcontent);
  94. // 设置超时时间
  95. curl_easy_setopt(m_pcurl, CURLOPT_TIMEOUT, 10);
  96. // 禁用掉alarm这种超时
  97. curl_easy_setopt(m_pcurl, CURLOPT_NOSIGNAL, 1L);
  98. // 禁止重用TCP连接
  99. curl_easy_setopt(m_pcurl, CURLOPT_FORBID_REUSE, 1);
  100. // 打开调试
  101. curl_easy_setopt(m_pcurl, CURLOPT_VERBOSE, 1);
  102. curl_easy_setopt(m_pcurl, CURLOPT_DEBUGFUNCTION, debug_callback);
  103. curl_easy_setopt(m_pcurl, CURLOPT_DEBUGDATA, &m_debugcontent);
  104. // 判断是否是需要代理
  105. if( m_strProxyServer.size() > 0 && m_nPort > 0)
  106. {
  107. // 打开,允许重用TCP连接
  108. curl_easy_setopt(m_pcurl, CURLOPT_FORBID_REUSE, 0);
  109. // 第一种方法
  110. curl_easy_setopt(m_pcurl,CURLOPT_PROXY,m_strProxyServer.c_str());
  111. curl_easy_setopt(m_pcurl, CURLOPT_PROXYPORT, m_nPort);
  112. curl_easy_setopt(m_pcurl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
  113. curl_easy_setopt(m_pcurl, CURLOPT_HTTPPROXYTUNNEL, 1L);
  114. }
  115. return TRUE ;
  116. }
  117. BOOL CVVCurl::ReleaseCurlHandle()
  118. {
  119. if( NULL != m_pcurl)
  120. {
  121. curl_easy_cleanup(m_pcurl);
  122. }
  123. m_pcurl = NULL ;
  124. return TRUE ;
  125. }
  126. BOOL CVVCurl::DeleteCookieFile()
  127. {
  128. ::DeleteFile(m_cookiepath.c_str());
  129. return TRUE ;
  130. }
  131. BOOL CVVCurl::OpenURL(std::string strURL,CURL_TYPE ntype)
  132. {
  133. return OpenURL(strURL,_T(""),ntype) ;
  134. }
  135. BOOL CVVCurl::OpenURL(std::string strURL,std::string strPostData,CURL_TYPE ntype)
  136. {
  137. m_headcontent = m_bodycontent = m_debugcontent = _T("");
  138. if( NULL == m_pcurl )
  139. {
  140. ASSERT(FALSE) ;
  141. return FALSE ;
  142. }
  143. if( ntype == CURL_POST || strPostData.size() > 0)
  144. {
  145. //curl_easy_setopt(m_pcurl,CURLOPT_HTTPGET,0);
  146. /* POST 数据 */
  147. curl_easy_setopt(m_pcurl,CURLOPT_POST,1);
  148. if(strPostData.size() > 0)
  149. {
  150. curl_easy_setopt(m_pcurl, CURLOPT_POSTFIELDS, strPostData.c_str());
  151. curl_easy_setopt(m_pcurl, CURLOPT_POSTFIELDSIZE, strPostData.size());
  152. }
  153. else
  154. {
  155. curl_easy_setopt(m_pcurl, CURLOPT_POSTFIELDS, NULL);
  156. curl_easy_setopt(m_pcurl, CURLOPT_POSTFIELDSIZE, 0);
  157. }
  158. //SetCurlHandleOpt() ;
  159. }else
  160. {
  161. // 禁用POST,直接GET请求
  162. //curl_easy_setopt(m_pcurl,CURLOPT_POST,0);
  163. //curl_easy_setopt(m_pcurl, CURLOPT_POSTFIELDS, NULL);
  164. curl_easy_setopt(m_pcurl,CURLOPT_HTTPGET,1);
  165. //SetCurlHandleOpt() ;
  166. }
  167. try
  168. {
  169. // 远程URL,支持 http, https, ftp
  170. curl_easy_setopt(m_pcurl, CURLOPT_URL, strURL.c_str());
  171. CURLcode nRet =  curl_easy_perform(m_pcurl);
  172. return CURLE_OK == nRet ;
  173. }
  174. catch (...)
  175. {
  176. }
  177. return FALSE ;
  178. }

2.4 编写代码

在使用CVVCurl封装类之前必须先调用函数cur_global_init进行全局初始化,再关闭时在调用函数curl_global_cleanup扫尾。我们可以在函数CTestlibCurlApp::InitInstance()中,添加这个两个函数,如下图:

然后就可以在程序的任何地方调用了CVVCurl类来访问网页了,比如我在一个函数响应出使用如下代码获取网页数据:

  1. void CTestlibCurlDlg::OnBnClickedVisitButton()
  2. {
  3. UpdateData(TRUE);
  4. m_Url = m_Url.Trim();
  5. if( m_Url.GetLength() <= 0)
  6. return ;
  7. CVVCurl vvcurl ;
  8. vvcurl.Init() ;
  9. if( vvcurl.OpenURL(m_Url.GetBuffer()))
  10. {
  11. m_ContentEdit.Clear() ;
  12. m_ContentEdit.SetSel(0,-1,FALSE);
  13. m_ContentEdit.ReplaceSel(vvcurl.GetBodyContent(),FALSE) ;
  14. }
  15. }

2.5 调试

编译程序,可能会有许多没有调试符号警告,这个是无所谓的。

  1. Linking...
  2. libcurld.lib(asyn-thread.obj) : warning LNK4204: 'c:\resource\vccode\testlibcurl\testlibcurl\debug\vc80.pdb' is missing debugging information for referencing module; linking object as if no debug info
  3. libcurld.lib(base64.obj) : warning LNK4204: 'c:\resource\vccode\testlibcurl\testlibcurl\debug\vc80.pdb' is missing debugging information for referencing module; linking object as if no debug info
  4. libcurld.lib(bundles.obj) : warning LNK4204: 'c:\resource\vccode\testlibcurl\testlibcurl\debug\vc80.pdb' is missing debugging information for referencing module; linking object as if no debug info
  5. libcurld.lib(conncache.obj) : warning LNK4204: 'c:\resource\vccode\testlibcurl\testlibcurl\debug\vc80.pdb' is missing debugging information for referencing module; linking object as if no debug info
  6. libcurld.lib(connect.obj) : warning LNK4204: 'c:\resource\vccode\testlibcurl\testlibcurl\debug\vc80.pdb' is missing debugging information for referencing module; linking object as if no debug info
  7. libcurld.lib(cookie.obj) : warning LNK4204: 'c:\resource\vccode\testlibcurl\testlibcurl\debug\vc80.pdb' is missing debugging information for referencing module; linking object as if no debug info
  8. libcurld.lib(curl_addrinfo.obj) : warning LNK4204: 'c:\resource\vccode\testlibcurl\testlibcurl\debug\vc80.pdb' is missing debugging information for referencing module; linking object as if no debug info

执行程序结果如下,测试HTTP访问和HTTPS访问:

3. 总结

我封装的CVVCurl访问类是可以支持HTTPS POST的,具体的请看下访问接口就可以了,此外还可以指定Cookie文件 ,是线程安全的封装类。如果需要支持多个账号同时登陆Web,那么只需要为每个不同的账号指定不同的Cookie文件就可以了。

对于抓取的网页内容,如果用的UTF8编码的网页内容可能需要进行编码转换一下,才能正确显示中文,工程中含有代码转换的类CStringConvert,已经加到工程代码中,可直接使用,如果还不懂的话,就请打发一杯咖啡钱给我,让老衲细细道来。【点此打发咖啡】[https://me.alipay.com/jekkay]

以上的测试工程代码,可以在下面网址中下载:

    1. :   VC2005使用含SSL的静态libcurl库代码工程
    2. :  http://download.csdn.net/detail/hujkay/6932541

【转】如何在Windows+VS2005使用最新静态libcurl 7.35.0获取网页数据,支持HTTPS的更多相关文章

  1. 如何在WINDOWS下编译BOOST C++库 .

    如何在WINDOWS下编译BOOST C++库 cheungmine 2008-6-25   写出来,怕自己以后忘记了,也为初学者参考.使用VC8.0和boost1.35.0.   1)下载boost ...

  2. 如何在Windows平台使用VS搭建C++/Lua的开发环境

    转自:http://ju.outofmemory.cn/entry/95358 本文主要介绍如何在Windows平台利用VS搭建C++/Lua开发环境.这里的“C++/Lua开发环境”主要指的是C++ ...

  3. (转)如何在Windows上安装多个MySQL

    原文:http://www.blogjava.net/hongjunli/archive/2009/03/01/257216.html 如何在Windows上安装多个MySQL 本文以免安装版的mys ...

  4. 如何在windows下安装GIT

    如何在windows下安装GIT 分步阅读 Git是一个免费的.开源的版本控制软件.在Windows上安装git,一般为msysgit,官方下载地址为 http://code.google.com/p ...

  5. 如何在Windows中打开多个Windows Media Player

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:如何在Windows中打开多个Windows Media Player.

  6. Redis简介以及如何在Windows上安装Redis

    Redis简介 Redis是一个速度非常快的非关系型内存数据库. Redis提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erla ...

  7. 如何在Windows 10上运行Docker和Kubernetes?

    如何在Windows 10上运行Docker和Kubernetes? 在Windows上学习Docker和Kubernetes,开始的时候会让你觉得无从下手.最起码安装好这些软件都不是一件容易的事情. ...

  8. Redis进阶实践之三如何在Windows系统上安装安装Redis(转载)

    Redis进阶实践之三如何在Windows系统上安装安装Redis 一.Redis的简介 Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括 ...

  9. 如何在 Windows 10 中搭建 Node.js 环境?

    [编者按]本文作者为 Szabolcs Kurdi,主要通过生动的实例介绍如何在 Windows 10 中搭建 Node.js 环境.文章系国内 ITOM 管理平台 OneAPM 编译呈现. 在本文中 ...

随机推荐

  1. 15.8.6 AUTO_INCREMENT Handling in InnoDB

    1 传统模式 innodb_autoinc_lock_mode (“traditional” lock mode) 2 连续模式 innodb_autoinc_lock_mode (“consecut ...

  2. AS3 转 Java

    不错,我就是as3转java的程序猿. 大概两年前加过as3的QQ群里,有很多群友说as3发展前景不好,很多要转语言.我当时也想转,一直苦于没机会.现在机会终于来了... 首先说明一点,as3并不会像 ...

  3. Device eth0 does not seem to be present, delaying initialization. 问题

    今天在复制vmware的时候 出现网卡无法启动 报错显示 Device eth0 does not seem to be present, delaying initialization. 这个错误原 ...

  4. 循序渐进Python3(十二) --1--  web框架之django

    Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为: 大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能 ...

  5. CSS预处理器Sass、LESS 和 Stylus

    CSS 预处理器技术已经非常的成熟,而且也涌现出了越来越多的 CSS 的预处理器框架.本文向你介绍使用最为普遍的三款 CSS 预处理器框架,分别是 Sass.Less CSS.Stylus. 首先我们 ...

  6. sql server 2008 外键关联的设置和取消

    直接上图片 选中表右击-设计 找到需要设置外键的字段.右击-关系,在弹出的对话框中点击添加 选择右边的小按钮点击.选择主键表和关联的主键ID,以及外建表的关联字段. 建立外键完成. 删除的话选中某个外 ...

  7. hdu4578 Transformation

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 题目大意:n个数(初始为0)m个操作,操作类型有4种,操作1把区间的每个数+a,操作2把区间的每 ...

  8. python第十九天-----Django进阶

    1.机智的小django为我你们提供了快捷的表单验证! from django.shortcuts import render, HttpResponse,redirect from django i ...

  9. asp.net web.config 设置Session过期时间

    在Asp.net中,可以有四处设置Session的过期时间:(原文作者:望月狼地址:http://www.cnblogs.com/wangyuelang0526/) 一.全局网站(即服务器)级 IIS ...

  10. linux用户管理

    管理用户的文件 添加用户组 添加用户 修改权限