C++(SOCKET)简单爬虫制作
先给出代码:(我使用的是VS编译器,需要在项目-》project属性-》
#include <iostream>
#include <stdio.h>
#include <string>
#include <cstdlib>
#include <fstream>
#include <WinSock2.h> using namespace std; #pragma warning(disable:4996)
//忽略VS特有警告
#pragma comment(lib, "ws2_32.lib")
//加载ws2_32.dll
#define BUFF_SIZE 1024 int ncount = ;
string host, pos; SOCKET ConnectFunc(string host, string pos) {
WSADATA wsaData;
SOCKET serv;
//创建套接字
if (WSAStartup(MAKEWORD(, ), &wsaData) != ) {//初始化DLL
cout << "WSAStartup() Failed:" << WSAGetLastError() << endl;
system("PAUSE");
return -;
} serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//初始化套接字
if (serv == INVALID_SOCKET) {
cout << "socket() Failed:" << WSAGetLastError() << endl;
system("PAUSE");
return -;
} struct hostent *pt = gethostbyname(host.c_str());//解析域名IP
if (!pt) {
cerr << "Get IP Error!!!" << endl;
system("PAUSE");
return -;
}
struct sockaddr_in serv_addr;
//创建结构体sockaddr_in结构体变量,绑定套接字
memcpy(&serv_addr.sin_addr, pt->h_addr, );
//自动响应服务器IP
serv_addr.sin_family = AF_INET;
//IPv4
serv_addr.sin_port = htons();
//端口 /*输出服务器IP
for (int i = 0; pt->h_addr_list[i]; i++) {
printf("IP addr %d: %s\n", i + 1, inet_ntoa(*(struct in_addr*)pt->h_addr_list[i]));
}
*/ if (connect(serv, (LPSOCKADDR)&serv_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {//连接服务器
cout << "connect() Failed:" << WSAGetLastError() << endl;
system("PAUSE");
return -;
}//与服务器建立连接 string request = "GET " + pos + " HTTP/1.1\r\nHost:" + host + "\r\nConnection:Close\r\n\r\n";
//向服务器请求图片资源(发送到服务器的命令)
if (send(serv, request.c_str(), request.size(), ) == SOCKET_ERROR) {
cout << "send() Failed:" << WSAGetLastError() << endl;
closesocket(serv);
system("PAUSE");
return -;
}//发送指令消息 return serv;
//返回套接字
} void DownloadPicture() {
SOCKET serv_in = ConnectFunc(host, pos);
//连接服务器 char buffer[BUFF_SIZE] = { };
//数据缓存文件 string a = "G:\\Pictures\\", name;
cout << "picture name:";
cin >> name;
a = a + name + ".png";
//文件命名 FILE *fp = fopen(a.c_str(), "wb+");
//创建文件 if (NULL == fp) {
cerr << "Open File" << endl;
system("PAUSE");
exit(-);
} ncount = recv(serv_in, buffer, BUFF_SIZE, );
//跳过不需要信息(状态行和消息报头) char *infor = strstr(buffer, "\r\n\r\n");
//区分条件
fwrite(infor + strlen("\r\n\r\n"), sizeof(char), ncount - (infor - buffer) - strlen("\r\n\r\n"), fp);
//丢弃不需要数据
for (; (ncount = recv(serv_in, buffer, BUFF_SIZE, )) > ;) {
fwrite(buffer, sizeof(char), BUFF_SIZE, fp);
Sleep();
}//循环写入数据 fclose(fp);
//关闭文件流指针
closesocket(serv_in);
//断开连接,清除套接字
} int main()
{
CreateDirectory(L"G:\Pictures", NULL);
/*创建文件夹,如果程序报错就用下面这个
CreateDirectoryA("G:\Pictures", NULL);
*/ host = "images.cnblogs.com";
//cin >> host;
//输入要爬的网站地址
pos = "/cnblogs_com/Mayfly-nymph/1233628/o_images.png";
//cin >> pos;
//图片在服务器中的位置
DownloadPicture();
//下载图片
system("PAUSE");
return ;
}
程序中:
- 这里图片保存在G盘,没有G盘改成其他盘。
- 对文件命名可以替换成自动命名,比如命名:1.png, 2.png...
- 下载链接可以切换成输入,还可以加上一个循环(加上结束条件)。
- 数据操作可以用C++的,个人习惯C的。
思路(简单来说):
- 先把连接服务器的结构搭建好(作客户端),IP地址利用gethostbyname()函数获取。
- 向服务器发送获取资源命令。
- 接受数据并过滤不需要信息。
- 写入文件
1.搭建框架
首先我们将网络连接的一个结构搭建好:
WSADATA wsaData;
SOCKET serv; WSAStartup(MAKEWORD(, ), &wsaData) serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); struct hostent *pt = gethostbyname(host.c_str()); struct sockaddr_in serv_addr;
memcpy(&serv_addr.sin_addr, pt->h_addr, );
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(); connect(serv, (LPSOCKADDR)&serv_addr, sizeof(SOCKADDR)) send(serv, request.c_str(), request.size(), )
其中唯一需要注意的就是,IP地址的连接。因为我们输入的是域名,所以需要利用到gethostbyname()函数解析域名。(要了解这个函数:点击一下)
这是一个解析域名的小程序:
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib") int main(){
WSADATA wsaData;
WSAStartup( MAKEWORD(, ), &wsaData); struct hostent *host = gethostbyname("www.baidu.com");
if(!host){
puts("Get IP address error!");
system("pause");
exit();
} //别名
for(int i=; host->h_aliases[i]; i++){
printf("Aliases %d: %s\n", i+, host->h_aliases[i]);
} //地址类型
printf("Address type: %s\n", (host->h_addrtype==AF_INET) ? "AF_INET": "AF_INET6"); //IP地址
for(int i=; host->h_addr_list[i]; i++){
printf("IP addr %d: %s\n", i+, inet_ntoa( *(struct in_addr*)host->h_addr_list[i] ) );
} system("pause");
return ;
}
2.指令发送
我们与服务器成功连接之后,向服务器发送HTTP请求报头。
string request = "GET " + pos + " HTTP/1.1\r\nHost:" + host + "\r\nConnection:Close\r\n\r\n";
(借用)
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
详细了解:点击一下
3.获取资源
在接收和解释请求消息后,服务器会返回一个HTTP响应消息。
与HTTP请求类似,HTTP响应也是由三个部分组成,分别是:状态行,消息报头,相应正文。
状态行由协议版本,数字形式的状态代码,相应的状态描述组成,各元素之间以空格分隔,除了结尾的CRLF(回车换行)序列外,不允许出现CR或LF字符。格式如下:
HTTP-Version Status-Code Reason-Phrase CRLF
HTTP-Version表示服务器HTTP协议的版本,Status-Code表示服务器发回的响应代码,Reason-Phrase表示状态代码的文本描述,CRLF表示回车换行。
因为相应正文是我们需要的数据,所以我们需要将状态行和消息报头跳过。
消息报头与相应正文之间可以用\r\n\r\n进行区分,当第一次发现接收到的字符串数组中含有\r\n\r\n时,则将\r\n\r\n前的内容全部忽略,将剩下的内容写到文件中去。
ncount = recv(serv_in, buffer, BUFF_SIZE, ); char *infor = strstr(buffer, "\r\n\r\n"); fwrite(infor + strlen("\r\n\r\n"), sizeof(char), ncount - (infor - buffer) - strlen("\r\n\r\n"), fp);
再使用循环获取相应正文,将数据写入到创建的图片文件中。
for (; (ncount = recv(serv_in, buffer, BUFF_SIZE, )) > ;) {
fwrite(buffer, sizeof(char), BUFF_SIZE, fp);
Sleep();
}
这样一个简单的“爬虫”就实现了,没有正则表达式,也没有BFS,只是试试水。爬虫(图片)有兴趣可以看看这篇(点击进入) BFS(点击进入)
biubiubiu~有什么不懂可以加我问我,觉得可以就赞一个吧,你们是我最大的动力。
C++(SOCKET)简单爬虫制作的更多相关文章
- SOCKET简单爬虫实现代码和使用方法
抓取一个网页内容非常容易,常见的方式有curl.file_get_contents.socket以及文件操作函数file.fopen等. 下面使用SOCKET下的fsockopen()函数访问Web服 ...
- 简单爬虫,突破IP访问限制和复杂验证码,小总结
简单爬虫,突破复杂验证码和IP访问限制 文章地址:http://www.cnblogs.com/likeli/p/4730709.html 好吧,看题目就知道我是要写一个爬虫,这个爬虫的目标网站有 ...
- <node.js爬虫>制作教程
前言:最近想学习node.js,突然在网上看到基于node的爬虫制作教程,所以简单学习了一下,把这篇文章分享给同样初学node.js的朋友. 目标:爬取 http://tweixin.yueyishu ...
- Python简单爬虫入门三
我们继续研究BeautifulSoup分类打印输出 Python简单爬虫入门一 Python简单爬虫入门二 前两部主要讲述我们如何用BeautifulSoup怎去抓取网页信息以及获取相应的图片标题等信 ...
- [Java]使用HttpClient实现一个简单爬虫,抓取煎蛋妹子图
第一篇文章,就从一个简单爬虫开始吧. 这只虫子的功能很简单,抓取到”煎蛋网xxoo”网页(http://jandan.net/ooxx/page-1537),解析出其中的妹子图,保存至本地. 先放结果 ...
- Python简单爬虫入门二
接着上一次爬虫我们继续研究BeautifulSoup Python简单爬虫入门一 上一次我们爬虫我们已经成功的爬下了网页的源代码,那么这一次我们将继续来写怎么抓去具体想要的元素 首先回顾以下我们Bea ...
- GJM : Python简单爬虫入门(二) [转载]
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- python 简单爬虫diy
简单爬虫直接diy, 复杂的用scrapy import urllib2 import re from bs4 import BeautifulSoap req = urllib2.Request(u ...
- python3实现简单爬虫功能
本文参考虫师python2实现简单爬虫功能,并增加自己的感悟. #coding=utf-8 import re import urllib.request def getHtml(url): page ...
随机推荐
- 解决.jsp及静态资源文件访问404的问题
我们在做Web项目时,经常将.jsp文件放到webapp\WEB-INF下,这时,我们访问jsp等文件的时候,就会报404. 如果是纯前后端分离的项目,后端只返回数据,不处理页面,也没问题.但,有时我 ...
- [学习笔记]通过open函数改变标准输出的方法
int main(void) { char s[] = "abc.txt"; ; close(STDOUT_FILENO);//关闭标准输出文件描述符 int fd1 = open ...
- Spring 特点
IoC:豆浆和打针的例子.一个是主动的,一个是被动的.比如在spring里面我们需要对象了,提出需求,spring容器会把对象给你.(这就是IoC) AOP:
- Linux文件锁flock ,检测进程是否已经存在
在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock. 头文件:#include<sys/fil ...
- 使用穷人版profiler定位调试MySQL
此文已由作者温正湖授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 周末闲得蛋疼,来英飞特做人工空气净化器.开了电脑后,习惯性得点击xshell按钮,进入InnoSQL稳定性测 ...
- iOS开发--OC常见报错
1.解决RegexKitLite导入报错问题 2.The working copy "Test" failed to commit files.问题解决
- [A/C 2007] 数据备份(网络流,堆)
[A/C 2007] 数据备份(网络流,堆) 给你N各点的位置和K条链,需要用这些链把2K个点连起来,使得链的总长最短.可以随意选择要链的点.n=100000. 这道题居然可以用堆-- 首先,不能把区 ...
- 洛谷P4457/loj#2513 [BJOI2018]治疗之雨(高斯消元+概率期望)
题面 传送门(loj) 传送门(洛谷) 题解 模拟赛的时候只想出了高斯消元然后死活不知道怎么继续--结果正解居然就是高斯消元卡常? 首先有个比较难受的地方是它一个回合可能不止扣一滴血--我们得算出\( ...
- [51nod1190]最小公倍数之和V2(莫比乌斯反演)
题解 传送门 题解 我是真的不明白这玩意儿是怎么跟反演扯上关系的-- 首先 \[ \begin{align} ans &=b\sum_{d|b}{1\over d}\sum_{i=a}^{b} ...
- paramiko模块的安装和使用(含上传本地文件或文件夹到服务器,以及下载服务器文件到本地)
安装和使用分两步介绍: 介绍一下,本文的运行环境是win7 64位 和python 2.7 . 安装: WIN7_64位 安装python-ssh访问模块(paramiko)的安装教程,本人亲测下面 ...