C++写的socket网络爬虫,代码会在最后一次讲解中提供给大家,同时我也会在写的同时不断的对代码进行完善与修改

我首先向大家讲解如何将网页中的内容,文本,图片等下载到电脑中。

我会教大家如何将百度首页上的这个百度标志图片(http://www.baidu.com/img/bdlogo.gif)抓取下载到电脑中。

程序的部分代码如下,讲解在代码的下面,下载链接在最后给出,

int main()
{ string url = "www.baidu.com";
string name = "/img/bdlogo.gif";
int port = ;
int client_socket = makeSocket(url,port);//
string request = "GET " + name + " HTTP/1.1\r\nHost:" + url + "\r\nConnection:Close\r\n\r\n";// if (send(client_socket, request.c_str(), request.size(), ) == SOCKET_ERROR)//
{
cout << "send error" << endl;
} fstream file;
string fileName = FileName(name);//
file.open(fileName, ios::out | ios::binary);// char buf[];
::memset(buf, , sizeof(buf));//
int n = ;
n = recv(client_socket, buf, sizeof(buf)-sizeof(char), );//
char* cpos = strstr(buf, "\r\n\r\n");//
file.write(cpos + strlen("\r\n\r\n"), n - (cpos - buf) - strlen("\r\n\r\n"));//
while ((n = recv(client_socket, buf, sizeof(buf)-sizeof(char), )) > )//
{
try
{
file.write(buf, n);
}
catch (...)
{
cerr << "ERROR" << endl;
}
}
file.close();
closesocket(client_socket);
system("pause");
return ;
}

一、main函数

1、makeSocket(url,port)

int makeSocket(string host,int port)函数是我自己编写的,接受两个参数,一个是域名或主机名,第二个是所使用的端口号,返回一个用于创建socket的int型数据,将在这一页的二.makeSocket中进行讲解

2、string request = "GET " + name + " HTTP/1.1\r\nHost:" + url + "\r\nConnection:Close\r\n\r\n";

这个是http的请求报头,有很多的信息,这里只对这句话中使用到的进行讲解

GET 请求获取Request-URI所标识的资源;

name 所标识的资源;

HTTP/1.1 表示请求的HTTP协议版本;

Host:url  指定被请求资源的Internet主机和端口号,通常从HTTP URL中提取出来的,

比如 我们在浏览器中输入http://baidu.com/index.html浏览器发送的请求消息中,就会包含Host请求报头域,如下:
Host:www.baidu.com

此处使用缺省端口号80,若指定了端口号,则变成:Host:www.baidu.com:port

Connection:Close Connection字段用于设定是否使用长连接,在http1.1中默认是使用长连接的,即Connection的值为Keep-alive,如果不想使用长连接则需要明确指出connection的值为close

Connection:Close表明当前正在使用的tcp链接在请求处理完毕后会被断掉。以后client再进行新的请求时就必须创建新的tcp链接了,即必须从新创建socket

更多关于http协议的内容可以查考http://blog.csdn.net/gueter/article/details/1524447   HTTP协议详解

注意最后一定要以一个单独的\r\n作为结束标志

3.send/recv

send用于向服务端发送消息

recv/send函数原型如下

int recv(SOCKET s,char FAR * buf,int len,int flags)/int send(SOCKET s,const char FAR * buf,int len,int flags);

第一个参数表示代表对方的socket,

第二个参数为接收读取的信息的字符串

第三个参数为该字符串的大小

第四个参数可以用来控制读写操作

详情可以参照http://www.cnblogs.com/magicsoar/p/3587351.html 中的讲解1

4 FileName(name)

自己编写的string FileName(string dir)函数,由于windows中文件的名字中不允许含有/

所以FileName函数用于将dir中的所有/替换为_

string FileName(string dir)
{
string search = "/";
int pos = ;
while ((pos = dir.find(search, pos)) != string::npos) {
dir.replace(pos, search.size(), "_");
pos++;
}
return dir;
}

如string FileName(“img/bdlogo.gif”)返回_img_bdlogo.gif

5 file.open(fileName, ios::out | ios::binary)r45

ios::out以输出方式打开文件,如果文件不存在这创建新的文件

ios::binary以二进制模式进行I/O操作,这里使用二进制模式是为了正确的处理图片的下载

6 ::memset(buf, 0, sizeof(buf));

函数原型为void *memset(void *s, int ch, size n);

函数解释:将s所指的内存中前n个字节 (typedef unsigned int size_t)用 ch 替换并返回 s 。

memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体和数组进行清零操作的一种较快方法

7 在接收和解释请求消息后,服务器返回一个HTTP响应消息。

HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文

响应正文就是服务器返回的资源的内容,所以我们需要跳过状态行与消息报头部分。

消息报头与相应正文之间可以用\r\n\r\n进行区分,当第一次发现接收到的字符串数组中含有\r\n\r\n时,则将\r\n\r\n前的内容全部忽略,将剩下的内容写到文件中去

strstr(*str1, *str2)实现从字符串str1中查找是否有字符串str2,如果有,从str1中的str2位置起,返回str1中str2起始位置的指针,如果没有,返回null。

由于一次最多可以接受1024个字符,而\r\n极有可能位于中间位置,所有我们要将1024个char中位于\r\n之后的数据写到文件中。

二.makeSocket函数

int makeSocket(string host,int port)
{
WSADATA inet_WsaData;//
WSAStartup(MAKEWORD(, ), &inet_WsaData);//
if (LOBYTE(inet_WsaData.wVersion) != || HIBYTE(inet_WsaData.wVersion) != )//
{
WSACleanup();
return -;
}
int tcp_socket = socket(AF_INET, SOCK_STREAM, );//
struct hostent * hp = ::gethostbyname(host.c_str());//
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
memcpy(&saddr.sin_addr, hp->h_addr, );//3
if (connect(tcp_socket, (const struct sockaddr *)&saddr, sizeof(saddr)) == -)//
{
cerr << "error in connect" << endl;
}
return tcp_socket;
}

1 见http://www.cnblogs.com/magicsoar/p/3585129.html windows下的C++ socket服务器(3)中讲解

2 struct hostent * hp = ::gethostbyname(host.c_str());

gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针

hostent结构体的定义如下

struct  hostent {
        char    FAR * h_name;           /* official name of host */

char    FAR * FAR * h_aliases;  /* alias list */

short   h_addrtype;             /* host address type */

short   h_length;               /* length of address */

char    FAR * FAR * h_addr_list; /* list of addresses */

#define h_addr  h_addr_list[0]          /* address, for backward compat */

};

hostent->h_name表示的是主机的规范名。例如www.baidu.com的规范名其实是www.a.shifen.com。(关于www.a.shifen.com还有一段故事http://www.zhihu.com/question/20100901)

hostent->h_aliases表示的是主机的别名.www.google.com就是google他自己的别名。有的时候,有的主机可能有好几个别名,这些,其实都是为了易于用户记忆而为自己的网站多取的名字。

hostent->h_addrtype表示的是主机ip地址的类型,到底是ipv4(AF_INET),还是pv6(AF_INET6)

hostent->h_length表示的是主机ip地址的长度

hostent->h_addr_list表示的是主机的ip地址

#define h_addr h_addr_list[0]

3 memcpy(&saddr.sin_addr, hp->h_addr, 4);

由于 hp->h_addr是char*类型,不能直接赋值给saddr.sin_addr

所以我们使用了memcpy函数

函数原型如下

void *memcpy(void *dest, const void *src, size_t n);

从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。

程序的下载地址

http://files.cnblogs.com/magicsoar/Webcrawler1.rar

C++ socket网络爬虫(1)的更多相关文章

  1. Socket网络编程--网络爬虫(1)

    我们这个系列准备讲一下--网络爬虫.网络爬虫是搜索引擎系统中十分重要的组成部分,它负责从互联网中搜集网页,采集信息,这些网页信息用于建立索引从而为搜索引擎提供支持,它决定着整个引擎系统的内容是否丰富, ...

  2. Socket网络编程--网络爬虫(2)

    上一小节,我们实现了下载一个网页.接下来的一步就是使用提取有用的信息.如何提取呢?一个比较好用和常见的方法就是使用正则表达式来提取的.想一想我们要做个什么样的网络爬虫好呢?我记得以前好像博客园里面有人 ...

  3. Socket网络编程--网络爬虫(3)

    上一小节我们实现了从博客园的首页获取一些用户的用户名,并保存起来.接下来的这一小节我将对每个用户名构建一个用户的博客主页,然后从这个主页获取所有能获取到的网页,网页的格式现在是http://www.c ...

  4. C++ 实现网络爬虫

    吐槽 前天心血来潮, 把自己面试经历下了下来. 我觉得自己求职一路来比较心酸, 也付出了比一般人更多的汗水. 本以为写出来, 好歹可以作为一篇励志故事. 得到的评论却是, 语言只是一门工具. ||| ...

  5. Linux企业级项目实践之网络爬虫(1)——项目概述及准备工作

    我们在学习了Linux系统编程之后,需要一些实战项目来提高自己的水平,本系列我们通过编写一个爬虫程序,将我们学习的知识进行综合应用,同时在实现项目的过程中逐渐养成一些有用的思维方式,并具有初步的软件开 ...

  6. java假设模拟请求重新启动路由器(网络爬虫经常使用),还有java怎样下载图片

    我们假设在公司或家里使用网络爬虫去抓取自己索要的一些数据的时候,经常对方的站点有defence机制,会给你的http请求返回500错误,仅仅要是同样IP就请求不到数据,这时候我们仅仅能去重新启动路由器 ...

  7. python网络爬虫学习笔记

    python网络爬虫学习笔记 By 钟桓 9月 4 2014 更新日期:9月 4 2014 文章文件夹 1. 介绍: 2. 从简单语句中開始: 3. 传送数据给server 4. HTTP头-描写叙述 ...

  8. crawler_网络爬虫中编码的正确处理与乱码的解决策略

    转载: http://hi.baidu.com/erliang20088/item/9156132bdaeae8949c63d134 最近一个月一直在对nutch1.6版进行中等层次的二次开发,本来是 ...

  9. Python网络爬虫

    http://blog.csdn.net/pi9nc/article/details/9734437 一.网络爬虫的定义 网络爬虫,即Web Spider,是一个很形象的名字. 把互联网比喻成一个蜘蛛 ...

随机推荐

  1. python 集合总结

    ''' 集合:1:他是无序的,他是不重复的. 2,他里面的元素必须是可哈希的. int str bool ()但是它本身是不可哈希的. 3,集合不能更改里面的元素. 4,集合可以求交集,并集,差集,反 ...

  2. 基于 Keras 用 LSTM 网络做时间序列预测

    目录 基于 Keras 用 LSTM 网络做时间序列预测 问题描述 长短记忆网络 LSTM 网络回归 LSTM 网络回归结合窗口法 基于时间步的 LSTM 网络回归 在批量训练之间保持 LSTM 的记 ...

  3. 大数据入门第四天——基础部分之轻量级RPC框架的开发

    一.概述 .掌握RPC原理 .掌握nio操作 .掌握netty简单的api .掌握自定义RPC框架 主要内容 1.RPC是什么 RPC(Remote Procedure Call)—远程过程调用,它是 ...

  4. oracle rowid 研究

    SQL> create table tab01(id integer,val varchar(4)); Table created. SQL> insert into tab01 valu ...

  5. 会话控制(session和cookie)、跨页面传值

    1.session  登录上一个页面以后,长时间没有操作,刷新页面以后需要重新登录. 特点:(1)session是存储在服务器:   (2)session每个人(登陆者)存一份: (3)session ...

  6. 一维码Codabar简介及其解码实现(zxing-cpp)

    一维码Codabar:由4条黑色线条,3条白色线条,合计7条线条所组成,每一个字元与字元之间有一间隙Gap做区隔. 条形码Codabar包含21个字元: (1).10个数字0~9; (2)." ...

  7. Spring学习(十八)----- Spring AOP+AspectJ注解实例

    我们将向你展示如何将AspectJ注解集成到Spring AOP框架.在这个Spring AOP+ AspectJ 示例中,让您轻松实现拦截方法. 常见AspectJ的注解: @Before – 方法 ...

  8. 开箱即用 - log4net 日志

    废话少说,先上代码 log4net Demo 好的系统都有日志,log4net 是我在.net平台下用过最爽的日志库,简单易用.功能强大. 基于配置(配置很简单,一看就明,通用,拷去即用): 可同时保 ...

  9. 基于zookeeper实现分布式锁(续)

    测试代码: 效果图:

  10. Memcached服务器上实现多个实例(约约问题排查)

    约约测试服上出行一个问题,司机收车失败. (1)经查看代码是null指针异常. 针对,之前,同套代码发布到华威测试服,未出现该问题,遂认定不是代码问题. (2)打印异常信息,获取null值异常的收车司 ...