C++ socket网络爬虫(1)
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,
第二个参数为接收读取的信息的字符串
第三个参数为该字符串的大小
2024-10-10 20:50:37 原文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)的更多相关文章
- Socket网络编程--网络爬虫(1)
我们这个系列准备讲一下--网络爬虫.网络爬虫是搜索引擎系统中十分重要的组成部分,它负责从互联网中搜集网页,采集信息,这些网页信息用于建立索引从而为搜索引擎提供支持,它决定着整个引擎系统的内容是否丰富, ...
- Socket网络编程--网络爬虫(2)
上一小节,我们实现了下载一个网页.接下来的一步就是使用提取有用的信息.如何提取呢?一个比较好用和常见的方法就是使用正则表达式来提取的.想一想我们要做个什么样的网络爬虫好呢?我记得以前好像博客园里面有人 ...
- Socket网络编程--网络爬虫(3)
上一小节我们实现了从博客园的首页获取一些用户的用户名,并保存起来.接下来的这一小节我将对每个用户名构建一个用户的博客主页,然后从这个主页获取所有能获取到的网页,网页的格式现在是http://www.c ...
- C++ 实现网络爬虫
吐槽 前天心血来潮, 把自己面试经历下了下来. 我觉得自己求职一路来比较心酸, 也付出了比一般人更多的汗水. 本以为写出来, 好歹可以作为一篇励志故事. 得到的评论却是, 语言只是一门工具. ||| ...
- Linux企业级项目实践之网络爬虫(1)——项目概述及准备工作
我们在学习了Linux系统编程之后,需要一些实战项目来提高自己的水平,本系列我们通过编写一个爬虫程序,将我们学习的知识进行综合应用,同时在实现项目的过程中逐渐养成一些有用的思维方式,并具有初步的软件开 ...
- java假设模拟请求重新启动路由器(网络爬虫经常使用),还有java怎样下载图片
我们假设在公司或家里使用网络爬虫去抓取自己索要的一些数据的时候,经常对方的站点有defence机制,会给你的http请求返回500错误,仅仅要是同样IP就请求不到数据,这时候我们仅仅能去重新启动路由器 ...
- python网络爬虫学习笔记
python网络爬虫学习笔记 By 钟桓 9月 4 2014 更新日期:9月 4 2014 文章文件夹 1. 介绍: 2. 从简单语句中開始: 3. 传送数据给server 4. HTTP头-描写叙述 ...
- crawler_网络爬虫中编码的正确处理与乱码的解决策略
转载: http://hi.baidu.com/erliang20088/item/9156132bdaeae8949c63d134 最近一个月一直在对nutch1.6版进行中等层次的二次开发,本来是 ...
- Python网络爬虫
http://blog.csdn.net/pi9nc/article/details/9734437 一.网络爬虫的定义 网络爬虫,即Web Spider,是一个很形象的名字. 把互联网比喻成一个蜘蛛 ...
随机推荐
- 重学Verilog(3)——参数化模块
1.parameter方法 首先有这样一个模块 module half_adder(co,sum,a,b); output co,sum; input a,b; ; ; and #and_delay ...
- 数据结构与算法之排序(4)希尔排序 ——in dart
研究了网上大部分的希尔排序代码,发现大部分都是互相抄的——因为网上甚至某些书上的实现大部分都是错的.希尔排序是插入排序的升级版,通过引入间隔,然后分组进行插入排序.再逐步缩小间隔,直至间隔为1时,做全 ...
- OpenCV学习系列(一) Mac下OpenCV + xcode人脸检测实现
# OpenCV学习系列(一) Mac下OpenCV + xcode人脸检测实现 [-= 博客目录 =-] 1-学习目标 1.1-本章介绍 1.2-实践内容 1.3-相关说明 2-学习过程 2.1-环 ...
- 二级管工作原理(PN结原理)学习
0.小叙闲言 前面已经写了两篇介绍放大器应用和MOSFET作驱动的文章:常规放大电路和差分放大电路和MOSFET使用与H桥驱动问题.但是对它们的工作原理并没有进一步研究一下,今天写下这篇文章,主要是介 ...
- JavaScript总结(六)
使用DOM操纵样式表 ✍ 操纵元素的Style样式属性(所有的均对于CSS的内联式) 对于每个CSS样式,Style对象都包含了一个相对应的属性,只需要用到style属性即可: Div.style.c ...
- 用 eric6 与 PyQt5 实现python的极速GUI编程(系列03)---- Drawing(绘图)(3)-- 画线
[概览] 本文实现如下的程序:(在窗体中绘画出各种不同风格的线条) 主要步骤如下: 1.在eric6中新建项目,新建窗体 2.(自动打开)进入PyQt5 Desinger,编辑图形界面,保存 3.回到 ...
- 05- views视图层
1.配置index 主url from django.contrib import admin from django.urls import path, re_path, include urlpa ...
- sso(single sign on)介绍
1. 浏览器 > 2. 系统A(www.a.com) > 3. 系统B(www.b.com) > 4. 认证中心(www.sso.com) #### ** (1)首次访问** > ...
- [JOISC2018]道路建设 LCT
[JOISC2018]道路建设 LOJ传送门 考的时候打的大暴力,其实想到了LCT,但是思路有点没转过来.就算想到了估计也不能切,我没有在考场写LCT的自信... 其实这题不是让你直接用LCT维护答案 ...
- .net 控件生命周期
这里列举出来了11个生命周期,一般的控件生命周期会经历这11个生命周期,但是有一些特别的控件比如页面控件System.Web.UI.Page等. 具体代码参考如下: /// <summary&g ...