-
2016-09-08 18:19:40
(同步个人博客 http://sxysxy.org/blogs/28 到csdn
写一个网络爬虫
写一个网络爬虫,来获取一个网站上感兴趣的信息。
最基本的模型
- 就是图。每个页面看作一个节点,若页面A有到达页面B的链接,则添加一条由A到B的单向边。爬虫要遍历这张图。
遍历这张图
- 广度优先搜索即可。 不推荐用深度优先搜索(容易陷入单个分支而难以搜索到更广泛全面的信息) (如果不明白,请自行查询图论相关资料)
(以上noip普及组难度)但是细节(重点)
1 这不是OI题目,不会把节点以编号的形式给你。 一个页面只能通过它的网址认识它。由网页之间的关系构成的图中很可能(99.99…%)有环,搜索的时候要判重否则就会死在环里面。一个网址,是一个字符串,代表一个页面,如何快速判重? 字典树!
2 如何知道页面A有到达页面B的链接? 抓取页面A的网页源代码分析即可。重点便是html语句例如
href= "/blogs/3"
,表示A能到达页面/blogs/3/3 访问网络。windows: winsock2.h系列, linux: sys/socket.h系列。用TCP Socket简单地实现http即可。
一个简单的实现
https://github.com/sxysxy/httpSpider 这里我使用c语言做的一个简单的网络爬虫(已经完工)。 同时里面还有字典树和队列数据结构的实现。 httpSpider爬虫搜索遍历网站的同时,可以回调自定制的plugin.dll外挂dll的analyzer函数,将网站的数据发给它(这样泥就可以完成数据分析)。
本来想写个长篇大论的
但是比起什么可持久化树套树啊,FFT/NTT啊,这个真的没什么可多说的。
更多相关内容 -
网络爬虫知识教你“爬”遍各种网络
2021-05-24 07:17:25网络爬虫(Web crawler),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本,它们被广泛用于互联网搜索引擎或其他类似网站,可以自动采集所有其能够访问到的页面内容,以获取或更新这些网站的内容和检索...什么是网络爬虫?网络爬虫(Web crawler),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本,它们被广泛用于互联网搜索引擎或其他类似网站,可以自动采集所有其能够访问到的页面内容,以获取或更新这些网站的内容和检索方式。
内容一般分为两部分,非结构化的文本,或结构化的文本。
1. 关于非结构化的数据
1.1 HTML文本(包含JavaScript代码)
HTML文本基本上是传统爬虫过程中最常见的,也就是大多数时候会遇到的情况,例如抓取一个网页,得到的是HTML,然后需要解析一些常见的元素,提取一些关键的信息。HTML其实理应属于结构化的文本组织,但是又因为一般我们需要的关键信息并非直接可以得到,需要进行对HTML的解析查找,甚至一些字符串操作才能得到,所以还是归类于非结构化的数据处理中。
常见解析方式如下:
•CSS选择器
现在的网页样式比较多,所以一般的网页都会有一些CSS的定位,例如class,id等等,或者我们根据常见的节点路径进行定位,例如腾讯首页的财经部分。
•XPATH
XPATH是一种页面元素的路径选择方法,利用Chrome可以快速得到,如:
1.2 一段文本
一篇文章,或者一句话,我们的初衷是提取有效信息,所以如果是滞后处理,可以直接存储,如果是需要实时提取有用信息,常见的处理方式如下:
分词
根据抓取的网站类型,使用不同词库,进行基本的分词,然后变成词频统计,类似于向量的表示,词为方向,词频为长度。
NLP
自然语言处理,进行语义分析,用结果表示,例如正负面等。
2. 关于结构化的数据
结构化的数据是最好处理,一般都是类似JSON格式的字符串,直接解析JSON数据就可以了,提取JSON的关键字段即可。
3、爬虫爬取网页的基本步骤
1) 人工给定一个URL作为入口,从这里开始爬取。
万维网的可视图呈蝴蝶型,网络爬虫一般从蝴蝶型左边结构出发。这里有一些门户网站的主页,而门户网站中包含大量有价值的链接。
2) 用运行队列和完成队列来保存不同状态的链接。
对于大型数据量而言,内存中的队列是不够的,通常采用数据库模拟队列。用这种方法既可以进行海量的数据抓取,还可以拥有断点续抓功能。
3) 线程从运行队列读取队首URL,如果存在,则继续执行,反之则停止爬取。
4) 每处理完一个URL,将其放入完成队列,防止重复访问。
5) 每次抓取网页之后分析其中的URL(URL是字符串形式,功能类似指针),将经过过滤的合法链接写入运行队列,等待提取。
6) 重复步骤 3)、4)、5)。
4、主过程组成
在网络爬虫的系统框架中,主过程由控制器,解析器,资源库三部分组成。控制器的主要工作是负责给多线程中的各个爬虫线程分配工作任务。解析器的主要工作是下载网页,进行页面的处理,主要是将一些JS脚本标签、CSS代码内容、空格字符、HTML标签等内容处理掉,爬虫的基本工作是由解析器完成。资源库是用来存放下载到的网页资源,一般都采用大型的数据库存储,如Oracle数据库,并对其建立索引。
【控制器】
控制器是网络爬虫的中央控制器,它主要是负责根据系统传过来的URL链接,分配一线程,然后启动线程调用爬虫爬取网页的过程。
【解析器】
解析器是负责网络爬虫的主要部分,其负责的工作主要有:下载网页的功能,对网页的文本进行处理,如过滤功能,抽取特殊HTML标签的功能,分析数据功能。
【资源库】
主要是用来存储网页中下载下来的数据记录的容器,并提供生成索引的目标源。中大型的数据库产品有:Oracle、Sql Server等。
5、补充:
开源爬虫小知识
﹡DataparkSearch是一个在GNU GPL许可下发布的爬虫搜索引擎。
﹡GNU Wget是一个在GPL许可下,使用C语言编写的命令行式的爬虫。它主要用于网络服务器和FTP服务器的﹡镜像。
﹡Heritrix是一个互联网档案馆级的爬虫,设计的目标为对大型网络的大部分内容的定期存档快照,是使用java编写的。
﹡HTTrack用网络爬虫创建网络站点镜像,以便离线观看。它使用C语言编写,在GPL许可下发行。
﹡ICDL Crawler是一个用C++编写,跨平台的网络爬虫。它仅仅使用空闲的CPU资源,在ICDL标准上抓取整个站点。
﹡JSpider是一个在GPL许可下发行的,高度可配置的,可定制的网络爬虫引擎。
﹡LLarbin由Sebastien Ailleret开发;
﹡Methabot是一个使用C语言编写的高速优化的,使用命令行方式运行的,在2-clause BSD许可下发布的网页检索器。它的主要的特性是高可配置性,模块化;它检索的目标可以是本地文件系统,HTTP或者FTP。
﹡Nutch是一个使用java编写,在Apache许可下发行的爬虫。它可以用来连接Lucene的全文检索套件;
﹡Pavuk是一个在GPL许可下发行的,使用命令行的WEB站点镜像工具,可以选择使用X11的图形界面。与wget和httprack相比,他有一系列先进的特性,如以正则表达式为基础的文件过滤规则和文件创建规则。
﹡WebSPHINX(Miller and Bharat, 1998)是一个由java类库构成的,基于文本的搜索引擎。它使用多线程进行网页检索,html解析,拥有一个图形用户界面用来设置开始的种子URL和抽取下载的数据;
﹡WIRE-网络信息检索环境(Baeza-Yates 和 Castillo, 2002)是一个使用C++编写,在GPL许可下发行的爬虫,内置了几种页面下载安排的策略,还有一个生成报告和统计资料的模块,所以,它主要用于网络特征的描述;
﹡Ruya是一个在广度优先方面表现优秀,基于等级抓取的开放源代码的网络爬虫。在英语和日语页面的抓取表现良好,它在GPL许可下发行,并且完全使用Python编写。按照robots.txt有一个延时的单网域延时爬虫。
﹡Universal Information Crawler快速发展的网络爬虫,用于检索存储和分析数据;
﹡Agent Kernel,当一个爬虫抓取时,用来进行安排,并发和存储的java框架。
未来,最贵的东西将是数据。所以,掌握爬虫技术非常重要。
-
C语言爬虫
2021-05-19 17:18:01} void main() { //初始化socket,用于tcp网络连接 WSADATA wsaData; if( WSAStartup(MAKEWORD(2,2), &wsaData) != 0 ){ return; } //创建文件夹,保存图片和网页文本文件 CreateDirectory( "./img",0); Create...//#include #include
#include
#include
#include
#include "winsock2.h"
#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
using namespace std;
#define DEFAULT_PAGE_BUF_SIZE 1048576
queue hrefUrl;
hash_set visitedUrl;
hash_set visitedImg;
int depth=0;
int g_ImgCnt=1;
//解析URL,解析出主机名,资源名bool ParseURL( const string & url, string & host, string & resource){
if ( strlen(url.c_str()) > 2000 ) {
return false;
}
const char * pos = strstr( url.c_str(), "http://" );
if( pos==NULL ) pos = url.c_str();
else pos += strlen("http://");
char pHost[100];
char pResource[2000];
if( strstr( pos, "/")==0 )
{
pResource[0]='/';pResource[1]=0;
strcpy(pHost,pos);
}
else
sscanf( pos, "%[^/]%s", pHost, pResource );//以%s的形式读取, %[^a]表示匹配非a的任意字符,直到遇到a停止读入//这里pHost取“http://”后面到第一个‘/’之间的字符串,从第一个‘/’到结束都传给pResource host = pHost;
resource = pResource;
return true;
}
//使用Get请求,得到响应bool GetHttpResponse( const string & url, char * &response, int &bytesRead ){
string host, resource;
if(!ParseURL( url, host, resource )){
cout << "Can not parse the url"<
return false;
}
//建立socket struct hostent * hp= gethostbyname( host.c_str() );
if( hp==NULL ){
cout<< "Can not find host address"<
return false;
}
SOCKET sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP);
if( sock == -1 || sock == -2 ){
cout << "Can not create sock."<
return false;
}
//建立服务器地址 SOCKADDR_IN sa;
sa.sin_family = AF_INET;
sa.sin_port = htons( 80 );
//char addr[5];//memcpy( addr, hp->h_addr, 4 );//sa.sin_addr.s_addr = inet_addr(hp->h_addr); memcpy( &sa.sin_addr, hp->h_addr, 4 );
//建立连接 if( 0!= connect( sock, (SOCKADDR*)&sa, sizeof(sa) ) ){
cout << "Can not connect:"<< url <
closesocket(sock);
return false;
};
//准备发送数据 string request = "GET" + resource + "HTTP/1.1\r\nHost:" + host + "\r\nConnection:Close\r\n\r\n";//字符串拼接//发送数据 if( SOCKET_ERROR ==send( sock, request.c_str(), request.size(), 0 ) ){//request.size()=strlen(request.c_str) cout << "send error" <
closesocket( sock );
return false;
}
//接收数据 int m_nContentLength = DEFAULT_PAGE_BUF_SIZE;
char *pageBuf = (char *)malloc(m_nContentLength);
memset(pageBuf, 0, m_nContentLength);
bytesRead = 0;
int ret = 1;
cout <
while(ret > 0)
{
ret = recv(sock, pageBuf + bytesRead, m_nContentLength - bytesRead, 0);
if(ret > 0)
{
bytesRead += ret;
}
if( m_nContentLength - bytesRead<100)
{
cout << "\nRealloc memorry"<
m_nContentLength *=2;
pageBuf = (char*)realloc( pageBuf, m_nContentLength); //重新分配内存 }
cout << ret <
}
cout <
pageBuf[bytesRead] = '\0';
response = pageBuf;
closesocket( sock );
return true;
//cout<< response <
//提取所有的URL以及图片URLvoid HTMLParse ( string & htmlResponse, vector & imgurls, const string & host ){
//Sleep(10000);//找所有连接,加入queue中 const char *p= htmlResponse.c_str();
char *tag="href=\"";//href的内容 就是指要跳转的路由 或 方法 const char *pos = strstr( p, tag );
ofstream ofile("url.txt", ios::app);//以追加的方式打开文件 while( pos )
{
pos +=strlen(tag);
const char * nextQ = strstr( pos, "\"" );
if( nextQ )
{
char * url = new char[ nextQ-pos+1 ];
//char url[100];//固定大小的会发生缓冲区溢出的危险 sscanf( pos, "%[^\"]", url);
string surl = url; //转换成string类型,可以自动释放内存 if( visitedUrl.find( surl ) == visitedUrl.end() ){//visitedUrl.find( surl )=visitedUrl.end() 表示visitedUrl中没有sur1 visitedUrl.insert( surl );
ofile << surl<
hrefUrl.push( surl );//将sur1插到队列末 }
pos = strstr(pos, tag );
delete [] url; //释放掉申请的内存 }
}
ofile << endl << endl;
ofile.close();
tag ="
const char* att1= "src=\"";//规定图像|音视频等的 URL。 const char* att2="lazy-src=\"";//lazy_src=还是lazy-src= const char *pos0 = strstr( p, tag );
while( pos0 )
{
pos0 += strlen( tag );
const char* pos2 = strstr( pos0, att2 );
if( !pos2 || pos2 > strstr( pos0, ">") )
{
pos = strstr( pos0, att1);//非延迟加载项 if(!pos)
{
pos0 = strstr(att1, tag );
continue;
}
else
{
pos = pos + strlen(att1);
}
}
else //如果是延迟加载项 {
pos = pos2 + strlen(att2);
}
const char * nextQ = strstr( pos, "\"");
if( nextQ )
{
char * url = new char[nextQ-pos+1];
sscanf( pos, "%[^\"]", url);
cout << url<
string imgUrl = url;
if( visitedImg.find( imgUrl ) == visitedImg.end() )
{
visitedImg.insert( imgUrl );
imgurls.push_back( imgUrl );//imgurls作为模板队列,push_back的参数由单个字符变成string类型 }
pos0 = strstr(pos0, tag );
delete [] url;
}
}
cout << "end of Parse this html"<
}
//把URL转化为文件名string ToFileName( const string &url ){
string fileName;
fileName.resize( url.size());
int k=0;
for( int i=0; i
char ch = url[i];
if( ch!='\\'&&ch!='/'&&ch!=':'&&ch!='*'&&ch!='?'&&ch!='"'&&ch!=''&&ch!='|')
fileName[k++]=ch;
}
return fileName.substr(0,k) + ".txt";//从第0位开始,长度为k的字符串 + .txt}
//下载图片到img文件夹void DownLoadImg( vector & imgurls, const string &url ){
//生成保存该url下图片的文件夹 string foldname = ToFileName( url );
foldname = "./img/"+foldname;
if(!CreateDirectory( foldname.c_str(),NULL ))
cout << "Can not create directory:"<< foldname<
char *image;
int byteRead;
for( int i=0; i
{
//判断是否为图片,bmp,jgp,jpeg,gif string str = imgurls[i];
int pos = str.find_last_of(".");//返回值为相对于起点的偏移位 if( pos == string::npos )
continue;
else
{
string ext = str.substr( pos+1, str.size()-pos-1 );
if( ext!="bmp"&& ext!="jpg" && ext!="jpeg"&& ext!="gif"&&ext!="png")
continue;
}
//下载其中的内容 if( GetHttpResponse(imgurls[i], image, byteRead))
{
if ( strlen(image) ==0 )
{
continue;
}
const char *p=image;
const char * pos = strstr(p,"\r\n\r\n")+strlen("\r\n\r\n");
int index = imgurls[i].find_last_of("/");
if( index!=string::npos )
{
string imgname = imgurls[i].substr( index , imgurls[i].size() );
ofstream ofile( foldname+imgname, ios::binary );
if( !ofile.is_open() )
continue;
cout <
ofile.write( pos, byteRead- (pos-p) );
ofile.close();
}
free(image);
}
}
}
//广度遍历void BFS( const string & url ){
char * response;
int bytes;
//获取网页的相应,放入response中。 if( !GetHttpResponse( url, response, bytes ) ){
cout << "The url is wrong! ignore." << endl;
return;
}
string httpResponse=response;
free( response );
string filename = ToFileName( url );
ofstream ofile( "./html/"+filename );
if( ofile.is_open() ){
//保存该网页的文本内容 ofile << httpResponse << endl;
ofile.close();
}
vector imgurls;
//解析该网页的所有图片链接,放入imgurls里面 HTMLParse( httpResponse, imgurls, url );
//下载所有的图片资源 DownLoadImg( imgurls, url );
}
void main()
{
//初始化socket,用于tcp网络连接 WSADATA wsaData;
if( WSAStartup(MAKEWORD(2,2), &wsaData) != 0 ){
return;
}
//创建文件夹,保存图片和网页文本文件 CreateDirectory( "./img",0);
CreateDirectory("./html",0);
//string urlStart = "http://hao.";//遍历的起始地址//string urlStart = "http://www.wmpic.me/tupian";//string urlStart = "http://item.&id=36366887850&ns=1#detail"; string urlStart = "www.";
//使用广度遍历//提取网页中的超链接放入hrefUrl中,提取图片链接,下载图片。 BFS( urlStart );
//访问过的网址保存起来 visitedUrl.insert( urlStart );
while( hrefUrl.size()!=0 ){
string url = hrefUrl.front(); //从队列的最开始取出一个网址 cout << url << endl;
BFS( url ); //遍历提取出来的那个网页,找它里面的超链接网页放入hrefUrl,下载它里面的文本,图片 hrefUrl.pop(); //遍历完之后,删除这个网址 }
WSACleanup();
system("pause");
return;
}
-
如何优雅地使用c语言编写爬虫
2020-09-03 01:52:19如何优雅地使用c语言编写爬虫,本文介绍cspider爬虫库,这个cspider爬虫库的使命在于,我们能够使用c语言,依然能够优雅地编写爬虫程序,需要的朋友可以参考下 -
Linux C语言实现简单爬虫
2020-07-28 16:34:15文章目录代码案例源代码应用知识hostent结构体gethostbyname()函数inet_pton和inet_ntopinet_ptoninet_ntopsockaddr_inin_addr结构htons 编辑socket()connect()sprintf函数format标签属性setsockopt 代码案例 爬到的...文章目录
代码案例
爬到的HTML文件
输入终端的参数
源代码
/************************************************************************* > File Name: myphp.c > Author: 杨永利 > Mail: 1795018360@qq.com > Created Time: 2020年07月28日 星期二 11时50分24秒 ************************************************************************/ #include <stdio.h> #include <netdb.h> #include <arpa/inet.h> #include <string.h> int main(int argc, char* argv[]){ if(argc!=3) { printf("请输入正确的参数个数(运行文件,源网址,保存文件名)!\n"); return -1; } // 存放源网址的字符串 char *Char_Yuan=argv[1]; printf("你给的源网址是:%s\n",Char_Yuan); // 定义hostent结构体 /* struct hostent h_name – 地址的正式名称。 h_aliases – 空字节-地址的预备名称的指针。 h_addrtype –地址类型; 通常是AF_INET。 h_length – 地址的比特长度。 h_addr_list – 零字节-主机网络地址指针。网络字节顺序。 h_addr - h_addr_list中的第一地址。 */ struct hostent *host; // gethostbyname()函数用于获取主机名的包含主机名字和地址信息的hostent结构的指针 if((host=gethostbyname(Char_Yuan))== NULL){ printf("获取ip地址失败!\n"); return -1; } // 定义字符串用于存放转换后的网络地址 char buf[30]; // inet_ntop是将网络二进制结构到ASCII类型的地址 /* 第一个参数af是地址簇, 第二个参数*src是来源地址, 第三个参数* dst接收转换后的数据。 第四个参数三接收数据的长度 */ inet_ntop(host->h_addrtype,host->h_addr_list[0],buf,sizeof(buf)); // sockaddr结构体 /* 参数说明: sin_family指代协议族,在socket编程中只能是AF_INET sin_port存储端口号(使用网络字节顺序),在linux下,端口号的范围0~65535,同时0~1024范围的端口号已经被系统使用或保留。 sin_addr存储IP地址,使用in_addr这个数据结构 sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。 */ struct sockaddr_in server; // 初始化结构体变量 bzero(&server,sizeof(server)); // 为结构体变量的每个成员赋值 server.sin_family=AF_INET; server.sin_port=htons(80); server.sin_addr.s_addr=inet_addr(buf); // 根据目前数据,分配一个套接口的描述字及其所用的资源。 int sockfd=socket(AF_INET,SOCK_STREAM,0); // connect函数进行连接套接字 if(connect(sockfd, (struct sockaddr*)&server, sizeof(server))){ printf("connect() error!\n"); return -1; } // 定义套接字要进行发送的消息字符串 char socket_send_message[1024]; // 用sprintf函数将请求头写发送字符串 sprintf(socket_send_message,"GET / HTTP/1.1\r\nHost:%s\r\nAccept:*/* \r\nUser-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64)\r\nconnection:Keep-Alive\r\n\r\n", Char_Yuan); // 将缓冲区设置为两秒 int timeout=2000; /* setsockopt函数参数: sockfd:标识一个套接口的描述字。 level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。 optname:需设置的选项。 optval:指针,指向存放选项待设置的新值的缓冲区。 optlen:optval缓冲区长度。 */ setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); // 发送套接字 if(send(sockfd, socket_send_message, strlen(socket_send_message), 0) <= 0){ printf("send() error!\n"); return -1; } setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); // 定义套接字要进行接收的消息字符串 char socket_get_message[1024]; // 用于进行数据的接收 int str_len; // 将获取的消息写入html文件 FILE* file = fopen(argv[2], "a+"); if(file == NULL){ printf("fopen() error!\n"); return -1; } // 执行循环直到接收消息的最后 do{ //给定循环缓冲区一直接受,直到接受至最后 bzero(socket_get_message, sizeof(socket_get_message)); str_len = recv(sockfd, socket_get_message, sizeof(socket_get_message), 0); // 将每次接收的数据追加到文件中 fwrite(socket_get_message, 1, 1024, file); }while(str_len); return 0; }
应用知识
hostent结构体
定义
struct hostent{ char * h_name; char ** h_aliases; short h_addrtype; short h_length; char ** h_addr_list; #define h_addr h_addr_list[0]; };
参数
struct hostent
h_name – 地址的正式名称。
h_aliases – 空字节-地址的预备名称的指针。
h_addrtype –地址类型; 通常是AF_INET。
h_length – 地址的比特长度。
h_addr_list – 零字节-主机网络地址指针。网络字节顺序。
h_addr - h_addr_list中的第一地址。gethostbyname()成功时返回一个指向结构体 hostent 的指针,或者是个空(NULL)指针。(但是和以前不同,不设置errno,h_errno 设置错误信息。请看下面的herror()。
gethostbyname()函数
gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构的指针。结构的声明与gethostbyaddr()中一致。
返回对应于给定主机名的主机信息。#include <winsock2.h> struct hostent *gethostbyname(const char *name);
name:指向主机名的指针。
返回类型struct hostent { char *h_name; char ** h_aliases; short h_addrtype; short h_length; char ** h_addr_list; };
Linux版
#include <netdb.h> struct hostent *gethostbyname(const char *hostname);
gethostbyname()返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针。结构的声明与gethostbyaddr()中一致。
返回的指针指向一个由Windows Sockets实现分配的结构。应用程序不应该试图修改这个结构或者释放它的任何部分。此外,所有线程共用一份这个结构的拷贝(这里应该是每个线程一份拷贝,原文是这样的Furthermore, only one copy of this structure is allocated per thread, so the application should copy any information it needs before issuing any other Windows Sockets function calls.),所以应用程序应该在发出其他Windows Scokets API调用前,把自己所需的信息拷贝下来。
gethostbyname()实现没有必要识别传送给它的IP地址串。对于这样的请求,应该把IP地址串当作一个未知主机名同样处理。如果应用程序有IP地址串需要处理,它应该使用inet_addr()函数把地址串转换为IP地址,然后调用gethostbyaddr()来得到hostent结构。
返回:非空指针——成功,空指针——出错,同时设置h_errno
inet_pton和inet_ntop
函数作用
- inet_pton:转换字符串到网络地址
- inet_ntop:转换网络二进制结构到ASCII类型的地址
inet_pton
inet_pton:将“点分十进制” -> “二进制整数”
函数原型:
int inet_pton(int af, const char *src, void *dst);
参数:
这个函数转换字符串到网络地址,
第一个参数af是地址簇,
第二个参数src是来源地址,
第三个参数 dst接收转换后的数据。inet_pton 是inet_addr的扩展,支持的多地址族有下列:
af = AF_INET
src为指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函数将该地址转换为in_addr的结构体,并复制在dst中。
af = AF_INET6
src为指向IPV6的地址,函数将该地址转换为in6_addr的结构体,并复制在dst中。如果函数出错将返回一个负值,并将errno设置为EAFNOSUPPORT,如果参数af指定的地址族和src格式不对,函数将返回0。
inet_ntop
inet_ntop函数原型如下[将“二进制整数” -> “点分十进制”]
Linux下inet_pton和inet_ntop这2个IP地址转换函数,可以在将IP地址在“点分十进制”和“二进制整数”之间转换。而且,这2个函数能够处理ipv4和ipv6。算是比较新的函数了。
#include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
这个函数转换网络二进制结构到ASCII类型的地址,参数的作用和inet_pton相同,只是多了一个参数socklen_t cnt,他是所指向缓存区dst的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针,并将errno置为ENOSPC。
sockaddr_in
sockaddr_in(在netinet/in.h中定义):
struct sockaddr_in { short sin_family;/*Address family一般来说AF_INET(地址族)PF_INET(协议族)*/ unsigned short sin_port;/*Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/ struct in_addr sin_addr;/*IP address in network byte order(Internet address)*/ unsigned char sin_zero[8];/*Same size as struct sockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐*/ };
参数说明:
sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储端口号(使用网络字节顺序),在linux下,端口号的范围065535,同时01024范围的端口号已经被系统使用或保留。
sin_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
(s_addr按照网络字节顺序存储IP地址)然后用memset函数初始化就可以了
memset((char*)&mysock,0,sizeof(mysock));//初始化
sockaddr_in mysock; memset((char*)&mysock,0,sizeof(mysock)); mysock.sin_family=AF_INET; mysock.sin_port=htons(1234);//1234是端口号 mysock.sin_addr.s_addr=inet_addr("192.168.0.1");
in_addr结构
在linux下:
typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; };
htons 编辑
htons是将整型变量从主机字节顺序转变成网络字节顺序, 就是整数在地址空间存储方式变为高位字节存放在内存的低地址处。
u_shorthtons(u_short hostshort);
socket()
socket()函数用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源。如果协议protocol未指定(等于0),则使用缺省的连接方式。
对于使用一给定地址族的某一特定套接口,只支持一种协议。但地址族可设为AF_UNSPEC(未指定),这样的话协议参数就要指定了。协议号特定于进行通讯的“通讯域”。
#include <sys/socket.h> int socket( int af, int type, int protocol);
参数
- af:一个地址描述。仅支持AF_INET格式,也就是说ARPA Internet地址格式。
- type:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
- protocol:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
返回值:
若无错误发生,socket()返回引用新套接口的描述字。否则的话,返回INVALID_SOCKET错误,应用程序可通过WSAGetLastError()获取相应错误代码。connect()
connect()用于建立与指定socket的连接。
定义函数:
int connect(int sockfd, struct sockaddr * serv_addr, int addrlen);
- sockfd:标识一个套接字。
- serv_addr:套接字s想要连接的主机地址和端口号。
- addrlen:name缓冲区的长度。
返回值:成功则返回0, 失败返回-1, 错误原因存于errno 中.
sprintf函数
函数声明
int sprintf(char *string, char *format [,argument,...]);
参数列表
- string-- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
- format-- 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是%[flags][width][.precision][length]specifier
- [argument]…:根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。
功能
把格式化的数据写入某个字符串缓冲区。
返回值
如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。
sprintf 返回以format为格式argument为内容组成的结果被写入string的字节数,结束字符‘\0’不计入内。即,如果“Hello”被写入空间足够大的string后,函数sprintf 返回5。
format标签属性
format 标签属性是%[flags][width][.precision][length]specifier,具体讲解如下: [3]
sprintf格式的规格如下所示。[]中的部分是可选的。
%[指定参数][标识符][宽度][.精度]指示符- [指定参数] 处理字符方向。负号时表示从后向前处理。
- [标识符] 填空字元。 0 的话表示空格填 0;空格是内定值,表示空格就放着。
- [宽度]字符总宽度。为最小宽度。
- [精度] 精确度。指在小数点后的浮点数位数。
- 转换字符
%% 印出百分比符号,不转换。
%c 字符输出到缓冲区,不转换。
%d 整数转成十进位。
%f 倍精确度数字转成浮点数。
%o 整数转成八进位。
%s 字符串输出到缓冲区,不转换。
%x 整数转成小写十六进位。
%X 整数转成大写十六进位。
setsockopt
setsockopt()函数,用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。
#include <sys/types.h> #include <sys/socket.h> int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
参数说明
- sockfd:标识一个套接口的描述字。
- level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。
- optname:需设置的选项。
- optval:指针,指向存放选项待设置的新值的缓冲区。
- optlen:optval缓冲区长度。
-
simspider
2021-05-22 08:21:10简介simspider是一个轻巧的跨平台的网络爬虫引擎,它提供了一组C函数接口用于快速构建你自己的网络爬虫应用,同时也提供了一个可执行的爬虫程序用于演示函数接口如何使用。simspider只依赖于第三方函数库libcurl。... -
爬虫实战——爬取C语言100例
2021-06-07 18:49:13三、爬去代码并将代码进行装换 遇到问题: 代码块中,每一个字符都是有span进行包装 http://tools.jb51.net/code/jb51_c_format 这个方法可以直接把代码的值获取到,可以通过它来进行获取代码 思路一、直接模仿... -
用C/C 扩展Python语言_python 调用c语言 python实现简单爬虫功能_python实现简单爬虫
2021-05-21 12:41:06} 转载请注明:数据分析 » 用C/C 扩展Python语言_python 调用c语言 python实现简单爬虫功能_python实现简单爬虫 python实现简单爬虫功能 在我们日常上网浏览网页的时候,经常会看到一些好看的图片,我们就希望把... -
C语言Linux服务器网络爬虫项目(二)项目设计和通过一个http请求抓取网页的简单实现...
2018-04-05 21:48:00我们通过上一篇了解了爬虫具体要实现的工作之后,我们分析得出的网络爬虫的基本工作流程如下: 1.首先选取一部分精心挑选的种子URL; 2.将这些URL放入待抓取URL队列; 3.从待抓取URL队列中取出待抓取在URL,... -
古诗收集程序C语言
2015-01-05 20:53:34中科院分词系统,开发,古诗自动生成程序。 -
C语言模块化编程的代码示例
2021-05-20 02:43:30C语言模块化编程的代码示例C语言模块化编程的代码示例C语言模块化编程的代码示例老赵最近写了一个小代码,是关于C语言程序化编程的,挺有趣的,和大家分享一下啦。一、程序概述二、程序结构三、 具体代码1、主函数2... -
通过curl工具写的一个C语言版网页爬虫工具,主要在vim里方便使用!
2018-01-11 09:22:14目录生成spider.exe的可执行程序,或者直接使用我编译好的可执行程序,如下图所示: 1.3 工具的使用: 直接在cmd种运行 spider.exe可以查看帮助,不过建议直接使用即可命令参数: spider.exe ... -
Socket编程系列之4:Libcurl网络爬虫编程实战
2021-12-03 09:43:19ASIO网络编程入门实战Socket编程系列之6:Libuv网络编程入门实战----------------------------------------------------Socket编程系列之4:Libcurl网络爬虫编程实战我将带领大家分享Libcurl的源码编译及环境搭建;... -
C++编写爬虫脚本爬取网站图片
2020-11-04 14:39:31C++编写爬虫脚本爬取网站图片整体代码设计思路具体功能实现初始化网络库url中爬取图片获取网页源代码连接主机url中获取主机名和文件名html中提取连接html中提取图片链接获取并保存图片总结 爬虫是一种常用的技术手段... -
C语言和Python爬虫哪个好?老男孩IT教育
2020-12-02 18:39:52IT行业给大家的第一印象就是发展前景好、薪资待遇高,因此很多非计算机专业的小白都想要转行学习编程,而C语言和Python爬虫的选择便成为大家最关注的问题,学习C语言还是学习Python爬虫好呢?我们一起来看看吧。... -
学习C语言还是学习Python爬虫?
2020-11-23 20:42:46IT行业给大家的第一印象就是发展前景好、薪资待遇高,因此很多非计算机专业的小白都想要转行学习编程,而C语言和Python爬虫的选择便成为大家最关注的问题,学习C语言还是学习Python爬虫好呢?我们一起来看看吧。... -
C语言实现抓取网页源代码
2021-05-21 08:36:37#include #include #include #include #include #include #include #include #include int port = 80;int main(int argc,char **argv){char buffer[512];int isock;struct sockaddr_in pin;struct hostent *hptr;... -
使用Python制作爬虫程序总结
2019-08-15 14:55:59网络爬虫(又称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。如果把互联网就比作一张大网,而爬虫便是在这张网上爬来爬去的蜘蛛,如果它遇到自己需要的食物(所需要的资源... -
python网络爬虫:爬虫环境与爬虫简介
2021-04-26 19:25:09网络爬虫也被称为网络蜘蛛、网络机器人,是一个自动下载网页的计算机程序或自动化脚本。 网络爬虫就像一只蜘蛛一样在互联网上沿着URL的丝线爬行,下载每一个URL所指向的网页,分析页面内容。 爬虫的原理 (1)通用网络... -
爬虫代码matlab-Undergraduate-Study-Projects:上海交通大学本科在读项目集
2021-06-07 20:57:08爬虫代码matlab 本科学习项目 本资源库包括我在上海交通大学本科期间完成的四个典型项目。 1.交大BBS搜索引擎 ./SJTU BBS Search Engine 为了巩固在分布式编程课程中学到的知识,我实现了一个由Apache Hadoop支持的... -
C语言获取网页源代码的学习所得
2021-05-20 05:34:33刚开始是什么都不懂,现在写出来一段代码感觉略微有点意思了。下面我分享一下学习过程和自己的理解。整体过程大概就是如下情况:先搜了一下别人的写这个东西的代码。研究了一下代码中一些难理解的东西。慢慢就写出来... -
2019年学习C语言还是学Python爬虫?
2020-11-20 17:35:152019年学习C语言还是学Python爬虫?非计算机专业学习编程最重要的是兴趣,先学C语言还是学Python开发老司机给你一些意见,Python上手简单、开发环境交互性强、众多第三方库,比C/C++有更容易学。入门编程需要了解... -
python为什么叫爬虫?它可以用来做什么?
2021-05-23 02:42:53网络爬虫,可以理解成在互联网上面爬行的一只蜘蛛,而互联网就像一张大网一样,爬虫可以在这张大网上面爬来爬去,如果有遇到自己喜欢的猎物(资源)就会把它抓取下来。一些不常用的名字还有蚂蚁、自动索引、模拟程序... -
可以一边学python爬虫一边学c语言吗?
2020-11-25 06:58:07看你学Python的用途,如果你学Python并不深入,或者用来日常的办公、写个小爬虫什么的。那么数据结构真的不用学。但如果你是想深入进去或者找python相关的工作,那么数据结构是避免不了要学的www.mh456.com防采集。... -
Python网络爬虫
2020-12-06 13:56:11网友NO.524767Python网络爬虫与信息提取(实例讲解)课程体系结构: 1、Requests框架:自动爬取HTML页面与...提取页面关键信息 5、Scrapy框架:网络爬虫原理介绍,专业爬虫框架介绍 理念:The Website is the API ..... -
《自然语言处理实战入门》第二章: NLP前置技术----网络爬虫简介
2020-05-07 09:46:00我们平时做自然语言处理,机器学习,都是希望能够有丰富的...在合理合法 的前提下自然语言处理 的语料和其他机器学习模型训练数据需要的图片等等各类数据,我们其实都是可以通过网络爬虫的方式进行积累的。 文章大... -
网络爬虫基本原理
2018-01-16 05:47:25网络爬虫是捜索引擎抓取系统的重要组成部分。爬虫的主要目的是将互联网上的网页下载到本地形成一个或联网内容的镜像备份。这篇博客主要对爬虫以及抓取系统进行一个简单的概述。 一、网络爬虫的基本结构及工作流程... -
Visual Studio 2019 python 多线程爬虫程序print函数没反应
2021-04-10 23:15:47我用Visual Studio 2019 python3.7 写多线程爬虫的python 代码,按F5运行函数没有反应,附上我用来测试的代码,所有的print函数都没有输出,不知道为什么,求求了,来个大神... -
用c# 实现一个爬虫
2021-12-05 17:01:23爬虫是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本,简单来说就是模拟浏览器发送http 请求,然后获取数据 实战 目标网站:https://www.baidu.com/ 第一步 分析 打开浏览器的开发者工具,快捷键f12 ... -
网络爬虫获取数据的步骤【重点】
2021-12-07 10:30:49一文详解网络爬虫获取数据的步骤