最近项目需要用到网页抓取下载等,简单说就是编写一个可用的httpClient,故总结如下。
开发环境linux,开发语言C/C++。
在网上检索一番后,大致了解了,有如下2种方法:
1. 直接写socket程序,这个用C就可以满足需要。
大致思路是:由于http采用80端口,并且封装了TCP。所以对写过TCP Socket通信的童鞋也没啥生疏的。
首先先解析出目标url的主机ip,设定ip和端口号,建立TCP连接后,按照http协议进行数据收发和解析。
可参考1:http://blog.youkuaiyun.com/hejinwei_1987/article/details/7540500
参考2:http://coding.debuntu.org/c-linux-socket-programming-tcp-simple-http-client
2. 当然是站在别人"肩膀“上了,即使用第三方开发库。
目前linux下常用的有 wget 或 curl (libcurl)。
这2个用来干嘛?看看咯
网页抓取
(1)curl下载百度首页内容,保存在baidu_html文件中
curl http://www.baidu.com/ -o baidu_html
(2)wget下载百度首页内容,保存在baidu_html文件中
wget http://www.baidu.com/ -O baidu_html2
至于这2个有什么区别,应该怎么选自行选择,呵呵。
选择了libcurl,随后进行开发尝试。
>>>>>>>>>>>>>>>>>>>>>>>curl安装编译、测试、调试<<<<<<<<<<<<<<<<<<<<<<<<<
curl的安装编译注意事项:
1. 下载
官网下载最新版本 http://curl.haxx.se/download.html
2. 安装:指定安装路径,eg: /usr/local/curl
命令1: ./configure --prefix=/usr/local/curl
命令2:make
命令3:sudo make install
成功后可以看到lib库,已经安装在 /usr/local/curl/lib
在安装目录下/usr/local/curl下会有四个目录 bin include lib share 包含了所需的库、头文件等
注意:在lib目录下有我们需要的静态库(*.a)和动态库(libcurl.so)。
3. 测试
编写一个简单的curl网页下载C程序,编译、运行。
编译:
gcc -o get_http get_http.c -L. -lcurl
gcc -o get_http get_http.c -L/usr/local/curl/lib -lcurl
4.参考代码cpp
/ 采用CURLOPT_WRITEFUNCTION 实现网页下载并调用解析函数功能
// 返回值:struct WeatherInfo
#include "weather.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <string>
/**C库*/
#include <cstring>
//curl:
#include </usr/local/curl/include/curl/curl.h>
#include </usr/local/curl/include/curl/easy.h>
using namespace std;
//这个函数是为了符合CURLOPT_WRITEFUNCTION而构造的
/** 完成数据保存功能
* @brief libcurl接收到数据时的回调函数
*
* 将接收到的数据保存到本地文件中,同时显示在控制台上。
*
* @param [in] buffer 接收到的数据所在缓冲区
* @param [in] size 数据长度
* @param [in] nmemb 数据片数量
* @param [in/out] 用户自定义指针
* @return 获取的数据长度
*/
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userData)
{//userData为用户自定义指针,libcurl不对该指针作任何操作,它只是简单的传递该指针。
//但与curl_easy_setopt(curl, CURLOPT_WRITEDATA, userfile);联动,即userData传递的是userfile的值
// 在回调函数中调用数据解析处理
FILE *fp = (FILE *)userData;
size_t written = fwrite(buffer, size, nmemb, fp);
cout << (char *)buffer << endl;
return nmemb;
}
int main(int argc, char *argv[])
{
CURL *curl;
curl_global_init(CURL_GLOBAL_ALL);
curl=curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
FILE *userfile = fopen("dataCpp.txt", "abc"); //userfile
/**CURLOPT_WRITEFUNCTION 将后继的动作交给write_data函数处理**/
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); // 注册回调函数
curl_easy_setopt(curl, CURLOPT_WRITEDATA, userfile);// 设置自定义指针
curl_easy_perform(curl);
//perform后释放资源
fclose(userfile);
curl_easy_cleanup(curl);
curl_global_cleanup();
exit(0);
}
5.C++封装curl可能遇到问题:
即C里面的回调函数封装到C++中,可采用static静态函数处理。
static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userData)